Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use a variable in the replacement side of the Perl substitution operator?

I would like to do the following:

$find = "start (.*) end"; $replace = "foo \1 bar";  $var = "start middle end"; $var =~ s/$find/$replace/; 

I would expect $var to contain "foo middle bar", but it does not work. Neither does:

$replace = 'foo \1 bar'; 

Somehow I am missing something regarding the escaping.

like image 581
Manu Avatar asked Dec 25 '08 08:12

Manu


People also ask

How do I replace a value in Perl?

Perl: Use s/ (replace) and return new string [duplicate]

How do I search and replace in Perl?

Performing a regex search-and-replace is just as easy: $string =~ s/regex/replacement/g; I added a “g” after the last forward slash. The “g” stands for “global”, which tells Perl to replace all matches, and not just the first one.

What is substitution operator?

Substitution Operator or 's' operator in Perl is used to substitute a text of the string with some pattern specified by the user.

What is in Perl regex?

Regular Expression (Regex or Regexp or RE) in Perl is a special text string for describing a search pattern within a given text. Regex in Perl is linked to the host language and is not the same as in PHP, Python, etc. Sometimes it is termed as “Perl 5 Compatible Regular Expressions“.


2 Answers

On the replacement side, you must use $1, not \1.

And you can only do what you want by making replace an evalable expression that gives the result you want and telling s/// to eval it with the /ee modifier like so:

$find="start (.*) end"; $replace='"foo $1 bar"';  $var = "start middle end"; $var =~ s/$find/$replace/ee;  print "var: $var\n"; 

To see why the "" and double /e are needed, see the effect of the double eval here:

$ perl $foo = "middle"; $replace='"foo $foo bar"'; print eval('$replace'), "\n"; print eval(eval('$replace')), "\n"; __END__ "foo $foo bar" foo middle bar 

(Though as ikegami notes, a single /e or the first /e of a double e isn't really an eval(); rather, it tells the compiler that the substitution is code to compile, not a string. Nonetheless, eval(eval(...)) still demonstrates why you need to do what you need to do to get /ee to work as desired.)

like image 54
ysth Avatar answered Oct 14 '22 23:10

ysth


Deparse tells us this is what is being executed:

$find = 'start (.*) end'; $replace = "foo \cA bar"; $var = 'start middle end'; $var =~ s/$find/$replace/; 

However,

 /$find/foo \1 bar/ 

Is interpreted as :

$var =~ s/$find/foo $1 bar/; 

Unfortunately it appears there is no easy way to do this.

You can do it with a string eval, but thats dangerous.

The most sane solution that works for me was this:

$find = "start (.*) end";  $replace = 'foo \1 bar';  $var = "start middle end";   sub repl {      my $find = shift;      my $replace = shift;      my $var = shift;      # Capture first      my @items = ( $var =~ $find );      $var =~ s/$find/$replace/;      for( reverse 0 .. $#items ){          my $n = $_ + 1;          #  Many More Rules can go here, ie: \g matchers  and \{ }          $var =~ s/\\$n/${items[$_]}/g ;         $var =~ s/\$$n/${items[$_]}/g ;     }     return $var;  }  print repl $find, $replace, $var;  

A rebuttal against the ee technique:

As I said in my answer, I avoid evals for a reason.

$find="start (.*) end"; $replace='do{ print "I am a dirty little hacker" while 1; "foo $1 bar" }';  $var = "start middle end"; $var =~ s/$find/$replace/ee;  print "var: $var\n"; 

this code does exactly what you think it does.

If your substitution string is in a web application, you just opened the door to arbitrary code execution.

Good Job.

Also, it WON'T work with taints turned on for this very reason.

$find="start (.*) end"; $replace='"' . $ARGV[0] . '"';  $var = "start middle end"; $var =~ s/$find/$replace/ee;  print "var: $var\n"   $ perl /tmp/re.pl  'foo $1 bar' var: foo middle bar $ perl -T /tmp/re.pl 'foo $1 bar'  Insecure dependency in eval while running with -T switch at /tmp/re.pl line 10. 

However, the more careful technique is sane, safe, secure, and doesn't fail taint. ( Be assured tho, the string it emits is still tainted, so you don't lose any security. )

like image 31
Kent Fredric Avatar answered Oct 14 '22 21:10

Kent Fredric