2

我经常用

perl -pi -w -e 's/search/replace/g;' [filelist]

在 [filelist] 的所有文件中用“replace”替换每个出现的“search”。不幸的是,所有文件似乎都获得了更新的时间戳。即使“搜索”没有出现在文件中。我可以改变这是一个简单的方法吗?

4

3 回答 3

2

不容易,不。所发生的一切是 perl 正在用通过正则表达式的结果覆盖文件。

您可以使用更长的程序来做到这一点,但没有简单的标志可以阻止这种行为。

于 2012-05-01T16:22:40.103 回答
2

-i松散地:

rename($ARGV, "$ARGV$^I") or die $! if length $^I;
open(*ARGV, '<', "$ARGV$^I") or die $!;
open(*STDOUT, '>', $ARGV) or die $!;

如您所见,它总是立即替换现有文件。这就是所有打印件 ( -p) 发送其输出的地方。

两种选择:

  1. 使用临时文件。

    perl -e'
       $temp_qfn = "temp";
       open(my $fh_out, ">", $temp_qfn) or die $!;
       my $save;
       while (<>) {
          $save = 1 if s/search/replace/g;
          print($fh_out $_);
       } continue {
          if (eof) {  # Not eof()!
             close($fh_out);
             rename($temp_qfn, $ARGV) if $save;
             $save = 0;
             open(my $fh_out, ">", $temp_qfn) or die $!;
          }
       }
    
       close($fh_out);
       unlink($temp_qfn);
    ' file ...
    
  2. 将整个文件加载到内存中。

    perl -0777ne'
       if (s/search/replace/g) {
          open(my $fh_out, ">", $ARGV) or die $!;
          print($fh_out $_);
       }
    ' file ...
    

(以上两者都有各种可解决的错误处理问题。-i有一些相同的问题。)

于 2012-05-01T19:34:00.097 回答
1

perldoc perlrun

-i[*extension*]

指定由“ <>”构造处理的文件将被就地编辑。它通过重命名输入文件、按原始名称打开输出文件并选择该输出文件作为print()语句的默认文件来完成此操作。扩展名(如果提供)用于修改旧文件的名称以制作备份副本,遵循以下规则:

如果未提供扩展名,则不进行备份并覆盖当前文件。

强调我的。

为了解决这个问题,您需要编写一个程序,为 中的每个文件打开一个临时文件@ARGV,从原始文件中读取,进行替换,将行写入临时文件,并跟踪是否有任何替换更改了原线。当到达文件末尾时,如果任何s///调用导致更改,它会将临​​时文件重命名为原始文件。eof对此以及File::Temp模块都很有用。

于 2012-05-01T16:21:14.607 回答