我有这个:
perl -pi -e 'print "code I want to insertn" if $. == 2' *.php
将code I want to insert
行放在文件的第二行,这是我需要对每个PHP文件
如果我在包含PHP文件和非PHP文件的目录中运行它,它会做正确的事情,但只对一个PHP文件。我以为*.php
会将它应用于所有PHP文件,但它没有这样做。
我怎么写它,它会修改每个PHP文件在一个目录?如果有一种简单的方法可以递归地遍历所有目录,那就更好了。我不介意为每个目录运行Perl脚本,因为没有那么多,但不想手工编辑每个文件。
问题是Perl用于读取命令行上传递的文件的文件句柄ARGV
从未显式关闭,因此行号$.
只是在第一个文件结束后保持递增,并且永远不会返回到1。
通过关闭ARGV
来修复这个问题,当它到达文件结束时。Perl将重新打开它以读取列表中的下一个文件,因此重置$.
perl -i -pe 'print "code I want to insertn" if $. == 2; close ARGV if eof' *.php
如果您可以使用sed
,这应该可以工作:
sed -si '2iCODE YOU WANT TO INSERT' *.php
要递归地执行,可以尝试:
find -name '*.php' -execdir sed -si '2iCODE YOU WANT TO INSERT' '{}' +
使用File::Find
.
注意,我已经包含了3个完整性检查来验证事情实际上是按照你想要的方式处理的。
- 一开始脚本只会打印出找到的文件,直到你注释掉所有的返回。
- 脚本将保存备份,除非你取消unlink语句的注释。
- 最后,脚本将只处理一个文件,直到注释掉
exit
语句。
这三个检查只是为了在编辑整个目录树之前验证一切是否如您所愿。
use strict;
use warnings;
use File::Find;
my $to_insert = "code I want to insertn";
find(sub {
return unless -f && /.php$/;
print "Edit $File::Find::namen";
return; # Comment out once satisfied with found files
local $^I = '.bak';
local @ARGV = $_;
while (<>) {
print $to_insert if $. == 2 && $_ ne $to_insert;
print;
}
# unlink "$_$^I"; # Uncomment to delete backups once certain that first file is processed correctly.
exit; # Comment out once certain that first file is processed correctly
}, '.')