如何在不触及未更改的文件的情况下替换Perl中现有文件中的字符串

时间:2015-04-01 18:06:44

标签: perl file

使用

perl -pi -e 's/pattern/replacement/g' $(find src -type f)

很好,除了一件事:所有文件都被覆盖,即使是那些没有任何匹配的文件。这并不好,因为我经常在Emacs或Eclipse中打开它们,然后问我无聊的问题。有一种简单的方法可以防止触摸未更改的文件(在查找中使用grep的工作量太大,特别是对于复杂的模式)。

3 个答案:

答案 0 :(得分:4)

不是将每个文件传递给perl进行处理,而是自己预先选择它们。

查找其中包含pattern的文件:

grep -Plr 'pattern' src

然后使用它代替find调用:

perl -pi -e 's/pattern/replacement/g' $(grep -Plr pattern src)

或者甚至喜欢这样:

grep -Plr 'pattern' src | xargs perl -pi -e's/pattern/replacement/g'

这也可能更快,因为你没有不必要地处理文件。

答案 1 :(得分:4)

打开文件后-i的第一件事就是unlink,这意味着你不能对你不想修改的文件使用-i。< / p>

find src -type f -exec grep -Pl 'pattern' {} + |
   xargs perl -i -pe's/pattern/replacement/g'

当然,grep已经可以执行递归搜索,因此除非您需要使用find来过滤结果,否则您可以使用

grep -Plr 'pattern' src |
   xargs perl -i -pe's/pattern/replacement/g'

注意:cmd | xargs perl ...可以处理的文件多于perl ... $( cmd )

答案 2 :(得分:2)

  

-p

     

导致Perl在程序周围采用以下循环,这使得它迭代文件名参数,有点像sed:

LINE:
while (<>) {
    ... # your program goes here
} continue {
    print or die "-p destination: $!\n";
}
     

-i [延伸]

     

相当于

#!/usr/bin/perl
$extension = '.orig';
LINE: while (<>) {
    if ($ARGV ne $oldargv) {
       if ($extension !~ /\*/) {
           $backup = $ARGV . $extension;
       }
       else {
           ($backup = $extension) =~ s/\*/$ARGV/g;
       }
       rename($ARGV, $backup);
       open(ARGVOUT, ">$ARGV");
       select(ARGVOUT);
       $oldargv = $ARGV;
    }
    s/foo/bar/;
}
continue {
    print;  # this prints to original filename
}
select(STDOUT);

现在,这意味着您可以使用此骨架脚本,并在未进行替换的情况下修改还原备份。