Take the 2-minute tour ×

I'm trying to use a Perl one-liner to munge some output from grepping svn diff, so I can automatically test the files. We have a run_test.sh script that can take multiple PHP files prepended with 'Test" as its arguments.

So far I have the following which successfully prepends 'Test' to the file names

[gjempty@gjempty-rhel4 classes]$ svn diff | grep '(revision' | perl -wpl -e 's/(.*)\/(.*)$/$1\/Test$2/'
--- commerce/TestLCart.php      (revision 104387)
--- commerce/manufacturing/TestLRoutingData.php (revision 104387)

Now I'd just like to grab the file/path to pass it to our run_test.sh. I can finish it off with awk as below, but am trying to improve my Perl/one-liner skills. So how do I revise the perl one-liner to additionally extract only the file path?

 svn diff | grep '(revision' | perl -wpl -e 's/(.*)\/(.*)$/$1\/Test$2/' | awk '{print $2}' | xargs run_test.sh
share|improve this question
Great answers all, I've been paying attention to them as they get revised. Will things out tomorrow when I get back to work and will accept an answer then. –  George Jempty Nov 11 '10 at 1:12

3 Answers 3

up vote 4 down vote accepted

You're just wanting the file names, so svn st is what you want. Instead of getting large quantities of noise which could potentially contain (revision in it, and the main lines you want, you'll get it like this: M commerce/LCart.php. Then you can just chop off \S* (any number of non-whitespace characters) followed by \s* (any number of whitespace characters), and take what's left. You could do the \S*\s* differently, but that's the simplest way to get all cases.

svn st | perl -wpl -e 's|\S*\s*(.*)/(.*)$|$1/Test$2|'

(Switched it after posting from using s/// to s||| so the / doesn't need to be escaped; good idea, Axeman.)

share|improve this answer

You can get rid of the grep and the awk fairly easily.

svn diff | perl -wnl -e '/\(revision/ or next; m|(\S+)/(\S+)|; print "$1/Test$2";'

I changed the -p to -n. -p means while (<>) { <your code>; print $_; }, and -n is the same but without the print, since the new version has an explicit print instead.

Rather than an s/// substitution, I used an m// pattern match. I changed the delimiter to | to avoid backslashing the slash (a cause of Leaning Toothpick Syndrome). You can use almost any punctuation character you want.

\S is similar to . but matches only non-whitespace characters. Your .*s in the pattern were actually matching the entire chunks of the line before and after the slash, but the new pattern only matches the pathname of the file. Since the + is "greedy", the first one ($1) will get more string when there are multiple slashes in the pathname, the same as with your substitution pattern.

share|improve this answer

Better version:

  • No default print ( -n)
  • Extract substring first
  • Subst on that
  • print value

    perl -wnl -e '($_)=m{---\s+(\S+)} and s|/([^/]+)$|/Test$1| and print "$_\n";'

You don't need awk now. And adding '(revision to the expression,

perl -wnl -e '($_)=m{---\s+(\S+)\s+\(revision} and s|/([^/]+)$|/Test$1| and print "$_\n";'

you don't need grep either.

But I have several subversion tools I created, and if all you want are the changed files 'svn st' is better.

svn st | perl -wnle 'm/^[CM]\s+(\S+)/and$r=rindex($1,"/")+1and print substr($1,0,$r),"Test",substr($1,$r+1),"\n"'

This time I chose a rindex + substr method. Now, there's no regex backtracking.

share|improve this answer

Your Answer


