如何在Perl单行命令中用通配匹配大量文件,避开xargs/find等工具
解决Perl处理大量文件时的Shell通配符限制问题
当然可以用Perl内置的通配功能搞定,既能保留单次Perl运行的效率,还不用折腾xargs这类工具的引号问题。下面是两种实用方案:
方案一:简洁版(兼容-pi原地编辑)
直接在Perl的BEGIN块里提前展开通配符,替代Shell的通配处理:
perl -pi -e 'BEGIN { @ARGV = map { glob } @ARGV } s/hi/bye/' 'manyfiles*'
原理
- 单引号包裹的
manyfiles*会被原封不动传给Perl,避免Shell提前展开触发文件数量超限的问题 - BEGIN块在Perl开始处理文件前执行,用
glob函数把通配符模式展开成实际的文件列表,替换掉原来的@ARGV - 后续
-p和-i参数会正常工作,完全保留原地编辑的特性,和Shell正常展开通配符的效果一致
方案二:手动循环版(更灵活)
如果需要对文件做额外逻辑处理(比如跳过目录、过滤特定文件),可以手动遍历展开后的文件列表:
perl -e ' for my $file (glob shift) { # 示例:跳过非文件类型(比如目录) next unless -f $file; local @ARGV = ($file); local $^I = ".bak"; # 等同于-i.bak,生成备份文件 do { s/hi/bye/; print; } while <>; } ' 'manyfiles*'
原理
glob shift获取命令行传入的通配符模式,展开为文件数组- 循环处理每个文件,用
local @ARGV让<>操作符读取当前文件内容 local $^I设置原地编辑的备份后缀,和-i参数的效果完全一致
为什么原来的写法无效?
你尝试的perl -pi -e 's/hi/bye/' 'manyfiles*'之所以失败,是因为单引号阻止了Shell对通配符的展开——Perl会把manyfiles*当作单个文件名去尝试打开,而系统里根本不存在这个名字的文件,自然会报错。
内容的提问来源于stack exchange,提问作者Joshua Goldberg
相关产品推荐
相关产品推荐

