Как удалить большое количество файлов рекурсивно (Скрипт на Perl)

3232

Как удалить большое количество файлов рекурсивно (Скрипт на Perl)

Как удалить большое количество файлов рекурсивно (Скрипт на Perl)
Как удалить большое количество файлов рекурсивно (Скрипт на Perl)

Проблема и постановка задачи

Когда в linux в одном каталоге скапливается много файлов (более миллиона), то удалить их является нетривиальной задачей.

У меня случай несколько более сложный – в почтовом сервере в каждом почтовом ящике (каталоге на диске) пользователя миллионы файлов (писем) – задача удалить все файлы старше двух недель рекурсивно во всех ящиках.

Согласно вышеприведенному исследованию для решения задачи удаления большого количества файлов вполне годится Perl. По этому мной и был написан скрипт для рекурсивного удаления файлов с проверкой условия по каждому файлу.

Решение – Скрипт удаления файлов.

Использование:

recurse_rm.pl [-y] [<dirname>]

Ключ -y означает – не задвать вопроса при начале удаления файлов

Текст скрипта:

!!!!! для реального удаления раскомментировать строку 107 (unlink $filename;) !!!!!

#! /usr/bin/perl
#
# Скрипт удалят рекурсивно все файлы, у которых mtime сташе значения TIME_TO_KEEP
# если установлена переменная $delete_dirs то дополнительно удаляются пустые каталоги
#
# в самом низу скрипта есть процедура exclude_test в которую нужно добавить правила
# по которым будут пропускаться файлы
#
# !!!!! для реального удаления раскомментировать строку 108 (unlink $filename;) !!!!!
#
# $TIME_TO_KEEP в секундах!
# 1 min = 60 sec
# 1 hour = 3600 sec
# 24 hours= 86400 sec
# 7 days = 604800 sec
# 14 days = 1209600 sec
# 30 days = 2592000 sec

#
# ================== start of config constants =================
#

$debug = 1; # debug can be 0, 1, 2

$TIME_TO_KEEP=1209600; # время (в секундах) в течении которого хранить файлы, все что старше - удалить
#$TIME_TO_KEEP = 60;

#$DIR_NAME='/var/spool/mail/rusdc-archive'; # Каталог верхнего уровня с которого начать удаление
$DIR_NAME='/root/bin/test';

$delete_dirs = 0; # set to 1 if you want delete epty dirs too

#
# ================== end of config constants =================
#

$time_now=time;
$dirs_found=0;
$dirs_deleted=0;
$files_foud=0;
$files_deleted=0;

# command line parsing
print_usage() if (@ARGV == 0);

if (@ARGV == 1) {
    $DIR_NAME=@ARGV[0];
    print "Are you shure to recursive del files in $DIR_NAME? [y/n]";
    $desigion=<stdin>; chomp $desigion;
    exit if ($desigion ne "y");
}

if (@ARGV > 1) {
    $DIR_NAME=@ARGV[1];
    print_usage() if (@ARGV[0] ne "-y");
}

enter_dir ($DIR_NAME);

print " Dirs Found: $dirs_found \n Dirs Deleted: $dirs_deleted \n Files Found: $files_foud \n Files Deleted: $files_deleted\n";
exit;

# ================     enter_dir     ===================
sub enter_dir {

local $dir_name=$_[0];
local $filename;
local *DIR;
$dirs_found++;

print "enter_dir $dir_name\n"  if ($debug == 2);

opendir DIR, "$dir_name" || die;

while ($filename = readdir (DIR)) {

    next if ($filename =~ m/^\./); # дальше, если имя начинается с точки
    next if (exclude_test($filename) == 1 );

    if (-d ($dir_name."/".$filename)){ # если это каталог, то входим в него = рекурсия
    enter_dir ($dir_name."/".$filename);
    next;
    }

    if (-f ($dir_name."/".$filename)){ # если это файл, то вызываем процедуру обработки файлов
    examine_file (($dir_name."/".$filename));
    next;

    }
}
print "we close Dir $dir_name\n"  if ($debug == 2);
closedir (DIR);
if ($delete_dirs > 0) {$dirs_deleted++ if (rmdir ($dir_name));}
}

# ================     examine_file     ===================
sub examine_file {
local $filename=$_[0];

    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = stat("$filename");
    print "\t\t $filename ==  $mtime \n"  if ($debug == 2);
    print " Files Found: $files_foud \t Files Deleted: $files_deleted\n" if ($debug == 1);
    $files_foud++;
    if ($mtime < ($time_now - $TIME_TO_KEEP)){
    print ("delete:\t".$dir."/".$filename."\n") if ($debug == 2);
    $files_deleted++;
#   unlink $filename; # !!!!! для реального удаления раскомментировать эту строку !!!!!
    }
}

# ================     print_usage     ===================
sub print_usage{
 print " Usage: \t\t recurse_rm <dir>\n Or non-interactive: \t recurse_rm -y <dir>\n";
 exit;
}

# ================     exclude_test     ===================
# add here tests to exclude files you want
sub exclude_test {
local $filename=$_[0];
local $exclude=0;

$exclude=1 if ($filename =~ m/.*dovecot.*/);

if ($debug == 1)  {print "File $filename excluded\n" if ($exclude ==1)}
return $exclude;
}

источник