Peter O'Brien Peter O'Brien - 5 months ago 9
Perl Question

Search and replace unix command line, perl capture group empty

I'm trying to perform a recursive search and replace of file content.

Given the below in a number of files:

example:{
something: 'ha',
somethingElse: 'ah'
}


I'd like to end up with:

example:{
something: 'ha',
somethingElse: 'ah',
somethingNew: 'ah ha'
}


On Mac OS X, I am trying the following from command line from within a parent directory:

find . -type f -exec perl -p -i -e "s/somethingElse:(.*)/somethingElse:$1,\n\tsomethingNew: 'ah ha'/g" {} \;


It's almost working except the capture group is interpreted as blank resulting in:

example:{
something: 'ha',
somethingElse:,
somethingNew: 'ah ha'
}


What's the problem?

Also not tied to
perl
, I don't mind an alternative approach (can use
sed
for example)

Answer

Thanks to @123 for answer in the comments:

You need to use single quotes. The $1 is interpreted by bash before perl, therefore it is empty when perl sees it. Or just escape it, as you use single quotes in your replacement.

Thus translating to:

find . -type f -exec perl -p -i -e 's/somethingElse:(.*)/somethingElse:$1,\n\tsomethingNew: '\''ah ha'\''/g' {} \;

or:

find . -type f -exec perl -p -i -e "s/somethingElse:(.*)/somethingElse:\$1,\n\tsomethingNew: 'ah ha'/g" {} \;

It might also be wise to add a file extension when doing this, one guess why: you may perform accidentally from too high a directory and corrupt say version control files, i.e.

find . -type f -name '*.json' -exec perl -p -i -e "s/somethingElse:(.*)/somethingElse:\$1,\n\tsomethingNew: 'ah ha'/g" {} \;

The originally accepted answer which was deleted suggested \1 rather than $1. Whilst this worked it was noted as bad practice by other commenters.