tags:

views:

59

answers:

2

I've used this to update every file in a directory

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

It works fine but it seems to modify the access date of every *.php file in the directory - is there a way I can make it only modify the access of date of those files it's actually modified ?

+2  A: 

I'm assuming you mean modification time, not access time.

I do that by selecting which files to update:

egrep -l 'include\s?\(' *.php | xargs perl -pi -e ...
ysth
For safety it is best to use egrep -lZ ... | xargs -0 so that file names with whitespace don't cause problems.
Hudson
That's great, thanks. I used ...egrep -l 'include ?\(' *.php | xargs perl -pi -e 's/include\s?\(/include_once(/g' -0... and it worked perfectly.
A: 

Out of curiosity, I wrote an in-place editor with the intent of robustly handling all filenames and trying to avoid shell command-line length issues. The program below takes one or more directories (defaulting to the current directory if none are specified) and creates a find ... | xargs ... pipeline that attempts to give @ARGV only those PHP sources that need tweaking.

#! /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;
}

At this point, @ARGV may be empty, and if so we bail.

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

Otherwise, we mimic the processing of the -i switch, which must go through <> and print. The code at least warns about errors such as the filesystem running out of space rather than failing silently.

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

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

Sample run:

$ ./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)
Greg Bacon