提问人:tourist 提问时间:11/15/2023 更新时间:11/21/2023 访问量:105
如何在 Perl 中优化符号链接删除?
How can I optimize Symbolic Link Deletion in Perl?
问:
我正在开发一个 Perl 脚本来删除目录中的符号链接,我注意到当前使用 find 命令的方法需要相当长的时间。我正在寻找更有效的解决方案。
以下是当前的代码片段:
system("find '$dir' -type l -exec rm -f {} \\;");
我还尝试了使用取消链接和 glob 的替代方案:
unlink glob("$dir/*") if -e $dir;
然而,这两种方法似乎都有其缺点,我想知道是否有更优化的方法可以在 Perl 中实现符号链接删除。
- 是否有任何特定的优化可以应用于 find 命令?
- 有没有更有效的纯 Perl 解决方案来删除目录中的符号链接?
- 是否有任何专门从事目录遍历和链接操作的 Perl 模块可以提高性能?
任何关于优化删除过程的见解或建议将不胜感激。谢谢!
其他信息:
- 目录 ($dir) 通常包含大量符号链接。
- 我愿意使用 Perl 模块或可能提供更好性能的替代方法。
- 性能基准或示例将特别有用。
答:
使用 代替 传递给尽可能多的参数,而不是为每个文件执行一次:+
;
rm -f
system("find '$dir' -type l -exec rm -f {} \\+");
如果您知道需要在树中走多深,请使用,例如,这仅搜索顶层:-maxdepth M -mindepth N
system("find '$dir' -maxdepth 1 -mindepth 1 -type l -exec rm -f {} \\+");
评论
+
-delete
-exec rm ...
无需将外部进程拖入其中。该任务可以纯粹在perl中使用File::Find
遍历目录树来完成:find
rm
#!/usr/bin/env perl
use warnings;
use strict;
use File::Find;
my $dir = ...; # Fill in the blanks
find(sub { unlink $_ if -l $_ }, $dir);
评论
要清理单个目录,因此不是递归的,它只需要类似
-l && unlink for glob "$dir/*";
这将是如此之快,以至于性能有点难以衡量。您删除了多少个文件,多久删除一次?
上述后缀循环使用的一个明显缺点是无法正常检查错误。这很重要,尤其是在删除大量文件时,所以最好把它写出来for
for my $file (glob "$dir/*") {
if (-l $file) {
unlink $file or warn "Error unlinking $file: $!"
}
}
这样做确实会“影响”性能,但影响程度最低。
我想知道......该目录中总共有多少个条目(文件、目录、链接等)?如果数量过多,例如数十万,那么这本身可能会减慢爬行的遍历速度。扫描较大的目录当然需要更多时间,但如果条目数量变得非常多,系统可能会被击倒,可以这么说;shell 中的基本列表可能需要 10-20 分钟。
有一次,我发现如果这个数字真的过多,那么系统(等)受到的影响远远超过程序。如果这个观察结果普遍成立,或者至少在你的系统上也成立,那么在Perl中这样做会更好。ls
find
如果这真的是问题所在 - 文件数量过多 - 那么我想到两个选项。
File::Glob 库通过其bsd_glob提供了不对文件列表进行排序的方法
use File::Glob qw(:bsd_glob);
for my $file ( bsd_glob("$dir/*", GLOB_NOSORT) ) {
...
}
如果确实有很多文件,这应该会有所帮助。感谢 Shawn 的评论。
另一种可能性是避免一次构建完整的文件列表,这是通过在列表上下文中使用来完成的,就像在循环中一样。在标量上下文中迭代,一次获取一个文件名,如果您真的有 200 万个文件或类似文件,这值得一试glob
for
glob
while ( my $file = glob "$dir/*" ) {
if (-l $file) {
unlink $file or warn "Error unlinking $file: $!"
}
}
试着把这些都计时,并澄清这有多慢,以及你有多少文件和链接。
评论
glob
find(sub { unlink $_ or warn "WARNING: Failed to unlink $_: $!\n" if -l $_ }, $dir);
评论
find ... -type l -print0 | xargs rm -0f
可能会更快,因为它不会为每个文件生成一个新的实例,而是使用单个实例一次删除多个文件。您还可以将 File::Find 而不是 shell 与 perl 函数一起使用,并且根本不生成任何外部进程。rm
rm
find
-l
unlink
unlink ... if -e $dir
肯定有其缺点。你是说吗?if -l $dir