你有没有遇到过这样的需求:把某个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::Spec 或 Path::Tiny 避免斜杠问题。
小提醒:别忘了权限和符号链接
实际跑脚本时,可能会遇到没权限读的目录(比如 /root),或者死循环的符号链接。加个判断更稳:
if (-l $_) {
return; # 跳过软链接,防循环
}
if (!-r $_) {
warn "No read permission on $File::Find::name\n";
return;
}平时整理下载目录、清理日志、检查配置文件,这些小脚本随手一写,比手动操作快得多。下次看到一堆杂乱的文件,别急着拖进回收站,先写五行 Perl 看看里面到底有什么。