我正在尝试使用File :: Find来1)通过给定的文件夹和子文件夹,删除任何超过30天的文件,以及b)如果父文件夹在所有删除后为空,也删除它。
这是我的代码:
use strict;
use warnings;
no warnings 'uninitialized';
use File::Find;
use File::Basename;
use File::Spec::Functions;
# excluding some home brew imports
# go into given folder, delete anything older than 30 days, and if folder is then empty, delete it
my $testdir = 'C:/jason/temp/test';
$testdir =~ s#\\#/#g;
open(LOG, ">c:/jason/temp/delete.log");
finddepth({ wanted => \&myWanted, postprocess => \&cleanupDir }, $testdir);
sub myWanted {
if ($_ !~ m/\.pdf$/i &&
int(-M $_) > 30
)
{
my $age = int(-M $_);
my $path = $File::Find::name;
print LOG "age : $age days - $path\n";
unlink($path);
}
}
sub cleanupDir {
my $path = $File::Find::dir;
if ( &folderIsEmpty($path) ) {
print LOG "deleting : $path\n";
unlink($path);
} else {
print LOG "$path not empty\n";
my @files = glob("$path/*");
foreach my $file(@files){
print LOG "\t$file\n";
}
}
}
我原以为finddepth()会到达树的底部然后向上移动,但这并没有发生。该脚本在解压缩一些电子书内容的情况下运行,并未删除包含子文件夹的目录,即使所有文件都已删除。
age : 54 days - C:/jason/temp/test/mimetype
age : 54 days - C:/jason/temp/test/META-INF/container.xml
age : 54 days - C:/jason/temp/test/META-INF/ncx.xml.kindle
deleting : C:/jason/temp/test/META-INF
age : 54 days - C:/jason/temp/test/OEBPS/content.opf
age : 54 days - C:/jason/temp/test/OEBPS/cover.html
age : 54 days - C:/jason/temp/test/OEBPS/ncx.xml
age : 54 days - C:/jason/temp/test/OEBPS/pagemap.xml
age : 54 days - C:/jason/temp/test/OEBPS/t01_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t02_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t03_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t04_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t05_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t06_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t07_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t08_00_text.html
age : 54 days - C:/jason/temp/test/OEBPS/t08_01_text.html
age : 54 days - C:/jason/temp/test/OEBPS/media/cover.jpg
age : 54 days - C:/jason/temp/test/OEBPS/media/flamlogo.gif
age : 54 days - C:/jason/temp/test/OEBPS/media/logolnmb.jpg
age : 54 days - C:/jason/temp/test/OEBPS/media/stylesheet.css
deleting : C:/jason/temp/test/OEBPS/media
C:/jason/temp/test/OEBPS not empty
C:/jason/temp/test/OEBPS/media
C:/jason/temp/test not empty
C:/jason/temp/test/META-INF
C:/jason/temp/test/OEBPS
看起来像C:/ jason / temp / test / OEBPS / media /被删除了,但是在调用预处理函数时没有注册该删除。有关如何使其工作的任何想法?谢谢!
感谢, bp的
答案 0 :(得分:2)
在Miller
发表评论后,您无法unlink
目录。此外,File::Find
在调用chdir
之前会在节点的目录中执行wanted
。这意味着,在postprocess
子例程中,您正在尝试删除当前正在工作的目录。 Windows不会那样。
我会这样写。我已经对它进行了测试,但显然你应该非常小心删除磁盘存储内容。
use strict;
use warnings;
use autodie;
use File::Find;
use File::Spec::Functions;
my $testdir = 'C:\jason\temp\test';
open my $log, '>', 'C:\jason\temp\delete.log';
finddepth(\&wanted, $testdir);
sub wanted {
my $full_name = canonpath $File::Find::name;
if (-f) {
my $age = int(-M);
unless ( /\.pdf\z/ or $age <= 30) {
print $log "Age: $age days - $full_name\n";
unlink;
}
}
elsif (-d) {
my @contents = do {
opendir my ($dh), $_;
grep { not /\A\.\.?\z/ } readdir $dh;
};
rmdir unless @contents;
}
}
答案 1 :(得分:1)
我怀疑你实际上并没有删除目录。来自unlink
的{{3}}:
注意:
unlink
不会尝试删除目录,除非您是超级用户并且向Perl提供了-U
标志。即使满足这些条件,也要警告取消链接目录可能会对文件系统造成损害。最后,许多操作系统不支持在目录上使用unlink
。请改用rmdir
。
答案 2 :(得分:0)
我从不喜欢File::Find
,因为它只是一团糟。它吞噬了整个程序,因为它希望所有内容都在你的想要的子程序中。另外,我不喜欢我的一半代码分散在各处的事实。但是,每个Perl安装都标配其他工具。我必须做。
我更喜欢把我的所有文件都放到一个数组中。它保持代码清洁。我find
找到了。我在其他地方完成剩余的处理工作。我还嵌入了我的find命令中嵌入的想要的子例程。它将所有东西都放在一个地方。
此外,您无法使用unlink
删除目录。使用File::Path中的remove_tree
。那是一个标准模块。您还可以使用readdir
查看目录有多少个子目录。这是检查它是否为空的好方法:
use strict;
use warnings;
use feature qw(say);
use File::Find;
use File::Path qw(make_path remove_tree);
my $testdir = 'C:/jason/temp/test';
my $mdate_limit = 30;
my @files; # We'll store the files here
my %dirs; # And we'll track the directories that my be empty
#
# First find the files
#
find ( sub {
return unless -f; # We want just files.
return if -M < $mdate_limit; # Skip if we've modified since $mdate_limit days
push @files, $File::Find::name; # We're interested in this file,
$dirs{$File::Find::dir} = 1; # and the directory that file is in
}, $testdir );
#
# Delete the files that you've found
#
unlink @files;
#
# Go through the directories and see which are empty
#
for my $dir ( sort keys %dirs ) {
opendir my $dir_fh, $dir or next; # We'll skip bad reads
my @dir_files = readdir $dir_fh;
close $dir_fh;
if ( @dir_files <= 2 ) { # Directory is empty if there's only "." and ".." in it
remove_tree( $dir )
or warn qq(Can't remove directory "$dir"\n);
}
}
请注意,我已嵌入wanted
例程:
find ( sub {
return unless -d; # We want just files.
return if -M < $mdate_limit; # File hast been modified in the $mdate_limit days
push @files, $Find::File::name; # We're interested in this file
$dirs{$Find::File::dir} = 1; # The directory that file is in
}, $testdir );
另一种选择是:
file (\&wanted, $testdir);
sub wanted {
return unless -d; # Okay...
return if -M < $mdate_limit; # Um... Where's $mdate_limit defined?
push @files, $Find::File::name; # And @files?
$dirs{$Find::File::dir} = 1; # And %dirs?
}
问题是我的wanted
子例程包含三个全局变量。并且,我的find
命令可能与我的wanted
子例程分开。在3个月的时间内,您必须搜索所有代码才能找到wanted
例程。
而且,当你看到wanted
子程序时,有三个神秘的全局变量。他们在哪里定义?这是一个错误吗?
通过将子程序与我的find相结合,我保证find
命令所需的子程序不会偏离我的find
。另外,它隐藏了
没有什么可以阻止我删除里面的命令。
,在搜索时更改目录结构通常不是一个好主意但是,我喜欢我的find
命令只是找到我感兴趣的文件。我不希望我的程序中有1/2的内容被填充。它成为维护的噩梦。我会忍受一点低效率。可能需要一两秒才能加载我的@files
数组和一百万个文件,但只要我调试程序,我就会花费更长的时间。