你有没有遇到过这样的需求:把某个ref="/tag/182/" style="color:#643D3D;font-weight:bold;">文件夹里所有 .log 文件找出来,批量重命名;或者统计某个项目目录下有多少个 .pl 脚本?用 Windows 资源管理器点开一层层找,太累;写个批处理又不太顺手。这时候 Perl 就挺合适——它原生支持目录操作,几行代码就能递归扫完整个目录树。
最简单的目录遍历
Perl 里用 opendir 和 readdir 就能读一个目录:
opendir(my $dh, ".") or die "无法打开当前目录: $!";
while (my $file = readdir($dh)) {
next if $file =~ /^\./; # 跳过 . 和 ..
print "$file\n";
}
closedir($dh);这段代码会列出当前目录下的所有非隐藏文件和子目录(不含递归)。注意 readdir 返回的是不带路径的文件名,所以如果想判断是文件还是目录,得拼上路径再用 -f 或 -d 测试。
带路径的判断和过滤
比如只打印普通文件:
opendir(my $dh, "/var/log") or die "无法打开 /var/log: $!";
while (my $name = readdir($dh)) {
next if $name =~ /^\./;
my $path = "/var/log/$name";
print "$path\n" if -f $path;
}
closedir($dh);这里 -f $path 是 Perl 的文件测试操作符,类似 Shell 里的 [ -f ],返回真就说明是普通文件。
递归遍历整个目录树
想深入子目录?自己写个递归函数就行:
sub scan_dir {
my ($dir) = @_;
opendir(my $dh, $dir) or warn "跳过 $dir: $!" and return;
while (my $entry = readdir($dh)) {
next if $entry =~ /^\./;
my $full = "$dir/$entry";
if (-d $full) {
scan_dir($full); # 是目录,递归进去
} else {
print "$full\n" if $full =~ /\.conf$/; # 只输出 .conf 文件
}
}
closedir($dh);
}
scan_dir("/etc");这个函数会从 /etc 开始,一层层钻进子目录,最后把所有以 .conf 结尾的文件路径打印出来。你可以把结尾条件换成 \.pl$、^Makefile$ 或者 -s > 1024*1024(大于 1MB 的文件)。
更省事的办法:File::Find 模块
Perl 标准库里有个现成模块 File::Find,不用自己写递归逻辑:
use File::Find;
find(sub {
return unless -f; # 只处理文件
return unless /\.txt$/i; # 忽略大小写匹配 .txt
print "$File::Find::name\n"; # 完整路径
}, "/home/user/docs");运行后,$File::Find::name 就是当前文件的绝对路径,$_ 是文件名本身。这个模块在脚本中用起来干净利落,适合快速写个临时工具。
小提醒:Linux/macOS 下 Perl 通常自带;Windows 用户如果没装,可以去 perl.org 下个 Strawberry Perl,装好就能直接跑上面这些例子。