使用perl进行搜索和替换多个文件时保持时间戳

时间:2012-05-01 16:12:33

标签: perl file

我经常使用

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

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

3 个答案:

答案 0 :(得分:2)

不容易,不。所有发生的事情都是perl正在覆盖文件,结果是通过正则表达式。

你可以使用更长的程序来完成它,但是没有简单的标志可以阻止这种行为。

答案 1 :(得分:1)

来自perldoc perlrun

  

-i[*extension*]

     

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

     

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

强调我的。

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

答案 2 :(得分:1)

-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 ...
    
  3. (以上两种都有各种可解决的错误处理问题。-i有一些相同的问题。)