12

I'm having trouble with a backreference in my replacement text that is followed by a literal. I have tried the following:

perl -0pi -e "s/(<tag1>foo<\/tag1>\n\s*<tag2>)[^\n]*(<\/tag2>)/\1${varWithLeadingNumber}\2/" file.xml
perl -0pi -e "s/(<tag1>foo<\/tag1>\n\s*<tag2>)[^\n]*(<\/tag2>)/\g{1}${varWithLeadingNumber}\g{2}/" file.xml

The first of course causes problems because ${varWithLeadingNumber} begins with a number, but I thought the \g{1} construct in my second attempt above was supposed to solve this problem. I'm using perl 5.12.4.

jonderry
  • 23,013
  • 32
  • 104
  • 171
  • 4
    Are you sure your problem isn't with the shell? I'd enclose the script in single quotes except for the part collecting the shell variables, just to cut down on the number of backslashes to worry about. – Jonathan Leffler Sep 26 '11 at 18:32
  • I just tried, for example, `perl -0pi -e 's/(foo<\/tag1>\n\s*)[^\n]*(<\/tag2>)/\g{1}25\g{2}/' file.xml`, and the result was the same. The replacement text ends up being `g{1}25g{2}`. – jonderry Sep 26 '11 at 18:48

1 Answers1

21

Using \1, \2, etc in the replacement expression is wrong. \1 is a regular expression pattern that means "match what the first capture matched" which makes no sense in a replacement expression. Regular expression patterns should not be used outside of regular expressions! $1, $2, etc is what you should be using there.

After fixing \1, you have

perl ... -e'... s/.../...$1$varWithLeadingNumber.../ ...'

That said, I think varWithLeadingNumber is supposed to be a shell variable? You shouldn't have any problems if it's a Perl variable. If you're having the shell interpolate varWithLeadingNumber, the problem can be fixed using

perl ... -e"... s/.../...\${1}${varWithLeadingNumber}.../ ..."

Note that you will have problems if $varWithLeadingNumber contains "$", "@", "\" or "/", so you might want to use a command line argument instead of interpolation.

perl ... -pe'
   BEGIN { $val = shift; }
   ... s/.../...$1$val.../ ...
' "${varWithLeadingNumber}"

You could also use an environment variable.

export varWithLeadingNumber
perl ... -pe's/.../...$1$ENV{varWithLeadingNumber}.../'

or

varWithLeadingNumber=varWithLeadingNumber \
    perl ... -pe's/.../...$1$ENV{varWithLeadingNumber}.../'

If you did have a \1

s/...\1.../.../

you can avoid the problem a number of ways including

s/...(?:\1).../.../
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • This works if I do `perl -0pi -e 's/(foo<\/tag1>\n\s*)[^\n]*(<\/tag2>)/${1}'${varWithLeadingNumber}'${2}/' file.xml. Thanks. – jonderry Sep 26 '11 at 18:54
  • Only for limited values of `$varWithLeadingNumber`. I recommend against that. – ikegami Feb 11 '15 at 17:38