Go to content Go to menu Go to search

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

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

Когда в linux в одном каталоге скапливается много файлов (более миллиона), то удалить их является нетривиальной задачей.
Подробное описание проблемы и пути решения описаны в этом посте: [Так как же удалить миллионы файлов из одной папки?]{http://habrahabr.ru/post/157613/}

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

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

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

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

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

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

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

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

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#! /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;
}


при публикации материалов с данного сайта обратная ссылка на сайт обязательна.
valynkin.ru © no rights reserved