Как удалить большое количество файлов рекурсивно (Скрипт на 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; }