Perl遍历目录文件:几行代码搞定文件扫描

你有没有遇到过这样的需求:把某个ref="/tag/182/" style="color:#8B0506;font-weight:bold;">文件夹里所有 .log 文件找出来,批量重命名;或者统计某个项目目录下有多少个 .pl 脚本?用鼠标一个个点开太费劲,写个 Perl 脚本,三两分钟就跑完。

最简单的办法:glob

如果只是想扫一遍当前目录下的普通文件(不进子目录),glob 是最快的选择:

my @files = glob "*.txt";
for my $file (@files) {
print "$file\n";
}

这行 glob "*.txt" 就像你在终端敲 ls *.txt,会返回所有匹配的文件名。注意它不会递归进子目录,适合简单场景。

要进子目录?File::Find 更靠谱

真正干活时,往往得钻进整个目录树。Perl 自带的 File::Find 模块就是干这个的:

use File::Find;

find(sub {
return unless -f; # 只处理文件,跳过目录
print "$File::Find::name\n" if /\.pm$/;
}, "/home/user/project");

这里 $File::Find::name 是完整路径(比如 /home/user/project/lib/Utils.pm),而 $_ 是当前文件名(比如 Utils.pm)。上面这段代码会把 project 目录下所有以 .pm 结尾的文件路径都打印出来。

自己动手写递归?也行,但别硬刚

有人喜欢控制感,想自己写递归遍历。其实也不难,核心就是 opendir + readdir:

sub scan_dir {
my ($dir) = @_;
opendir my $dh, $dir or die "Can't open $dir: $!";
while (my $entry = readdir $dh) {
next if $entry =~ /^\.{1,2}$/; # 跳过 . 和 ..
my $path = "$dir/$entry";
if (-d $path) {
scan_dir($path); # 递归进子目录
} elsif (-f $path && $path =~ /\.conf$/) {
print "$path\n";
}
}
closedir $dh;
}

scan_dir("/etc");

这段代码会一层层钻进 /etc 下所有子目录,只打印出后缀是 .conf 的文件。注意路径拼接用的是 /,在 Windows 上建议用 File::SpecPath::Tiny 避免斜杠问题。

小提醒:别忘了权限和符号链接

实际跑脚本时,可能会遇到没权限读的目录(比如 /root),或者死循环的符号链接。加个判断更稳:

if (-l $_) {
return; # 跳过软链接,防循环
}
if (!-r $_) {
warn "No read permission on $File::Find::name\n";
return;
}

平时整理下载目录、清理日志、检查配置文件,这些小脚本随手一写,比手动操作快得多。下次看到一堆杂乱的文件,别急着拖进回收站,先写五行 Perl 看看里面到底有什么。