1

I am trying to use variable interpolation in a replacement string including $1, $2,... However, I can't get it to expand $1 into the replacement. I eventually will have the $pattern and $replacement variables be read from a configuration file, but even setting them manually doesn't work.

In the example script, you can see that the $1 (which should be 'DEF') is not expanded in $new_name, but it is in $new_name2 (without variables).

Adding an 'e' flag to the substitution doesn't help.

How do I fix this?

Matt

EXAMPLE CODE:

#!/usr/local/bin/perl
use strict;

my $old_name = 'ABC_DEF_GHI';

my $pattern = 'ABC_(...)_GHI';
my $replacement = 'CBA_${1}_IHG';

# using variables - doesn't work
my $new_name = $old_name;
$new_name =~ s|$pattern|$replacement|;

printf("%s --> %s\n", $old_name, $new_name);


# not using variables - does work
my $new_name2 = $old_name;
$new_name2 =~ s|ABC_(...)_GHI|CBA_${1}_IHG|;

printf("%s --> %s\n", $old_name, $new_name2);

OUTPUT:

ABC_DEF_GHI --> CBA_${1}_IHG
ABC_DEF_GHI --> CBA_DEF_IHG
Smern
  • 18,746
  • 21
  • 72
  • 90
MERM
  • 629
  • 7
  • 21
  • possible duplicate of [How to use a variable in the replacement side of the Perl substitution operator?](http://stackoverflow.com/questions/392643/how-to-use-a-variable-in-the-replacement-side-of-the-perl-substitution-operator) – ysth May 01 '13 at 20:20
  • The sol'n I went with was: `$new_name =~ s|$pattern|qq("$replacement")|ee;` – MERM May 03 '13 at 00:48

2 Answers2

2

You need to do this changes in your code:

my $replacement = '"CBA_$1_IHG"';  #note the single and double quotes
# ...
$new_name =~ s|$pattern|$replacement|ee;  #note the double "ee", double evaluation

See this SO answer for more information

Community
  • 1
  • 1
Miguel Prz
  • 13,718
  • 29
  • 42
  • see http://stackoverflow.com/questions/392643/how-to-use-a-variable-in-the-replacement-side-of-the-perl-substitution-operator/392717#392717 for explanation – ysth May 01 '13 at 20:20
  • Note that this can be used to execute arbitrary Perl code, since the second `e` stands for `eval`, as in `eval EXPR`. – ikegami May 01 '13 at 21:06
2

/e treat $replacement as Perl code. The Perl code $replacement simply returns the value it contains.

If you want to evaluate the contents of $replacement as Perl code, you need

s/$search/ my $s = eval $replacement; die $@ if $@; $s /e

which can be written as

s/$search/$replacement/ee

Note that since $replacement is expected to contain Perl code, it means that this can be used to execute arbitrary Perl code.

A better solution is to realise you are writing your own subpar templating system, and use an existing one instead. String::Interpolate understands the templating syntax you are currently using:

use String::Interpolate qw( interpolate );
s/$search/interpolate $replace/e
ikegami
  • 367,544
  • 15
  • 269
  • 518