Perl全局替换触及每个文件 - 如何阻止它?

时间:2010-08-22 22:29:37

标签: perl

我用它来更新目录中的每个文件

perl -pi -e 's/include\s?\(/include_once(/g' *.php

它工作正常,但它似乎修改了目录中每个* .php文件的访问日期 - 有没有办法让它只修改它实际修改过的那些文件的日期访问?

2 个答案:

答案 0 :(得分:2)

我假设您的意思是修改时间,而不是访问时间。

我通过选择要更新的文件来做到这一点:

egrep -l 'include\s?\(' *.php | xargs perl -pi -e ...

答案 1 :(得分:1)

出于好奇,我写了一个就地编辑器,目的是强健地处理所有文件名,并试图避免shell命令行长度问题。下面的程序需要一个或多个目录(如果没有指定,则默认为当前目录)并创建一个find ... | xargs ...管道,试图仅为那些需要调整的PHP源提供@ARGV

#! /usr/bin/perl

use warnings;
use strict;

BEGIN {
  @ARGV = (".") unless @ARGV;

  my $xargspid = open my $xargs, "-|";
  die "$0: fork: $!" unless defined $xargspid;

  my @paths;
  if ($xargspid) {
    local $/ = "\0";
    while (<$xargs>) {
      chomp;
      push @paths => $_;
    }
    unless (close $xargs) {
      my $status = $? >> 8;
      die "$0: xargs exited $status"
        if $status != 0 && $status != 123;
    }
  }
  else {
    my $findpid = open my $find, "-|";
    die "$0: fork: $!" unless defined $findpid;

    if ($findpid) {
      open STDIN, "<&", $find or die "$0: dup find: $!";
      exec "xargs", "--null", "egrep", "-lZ", 'include[[:space:]]*\('
        or die "$0: exec xargs: $!";
    }
    else {
      exec "find", @ARGV, "-maxdepth", 1,
                          "-name", "*.php",
                          "-print0"
        or die "$0: exec find: $!";
    }
  }

  @ARGV = @paths;
}

此时,@ARGV可能为空,如果是,我们会保释。

unless (@ARGV) {
  warn "$0: nothing to do\n";
  exit 1;
}

否则,我们会模仿-i开关的处理,该开关必须经过<>print。代码至少会警告错误,例如文件系统空间不足而不是静默失败。

# $^I = "";  # no backup
$^I = ".bak";

while (<>) {
  s/include\s*\(/include_once(/g;
  print;
}
continue {
  if (eof) {
    close ARGV or warn "$0: close $ARGV: $!\n";
  }
}

示例运行:

$ ./fixinc

$ ls *.php
bar.php  baz.php  foo.php

$ ls *.bak
bar.php.bak  foo.php.bak

$ diff -ub foo.php.bak foo.php
--- foo.php.bak
+++ foo.php
@@ -1 +1 @@
-include(foo)
+include_once(foo)

$ diff -ub bar.php.bak bar.php
--- bar.php.bak
+++ bar.php
@@ -1 +1 @@
-include (bar)
+include_once(bar)