cruelmonk has asked for the wisdom of the Perl Monks concerning the following question:

Greetings fellow monks,


I'm currently writing an extended search and replace script.
Now, my script takes a couple of commandline params and then does the search and replace in a specific or multiple files.

./replace.pl -s SEARCHPATTERN -r REPLACESTRING FILENAME

I want to allow usage of regular expressions in this script, so that you could do something like :

./replace.pl -s "<html(.*)>" -r "<head$1>"

now, for some weird reason the '$1' apparantly gets evaluated by Getopt::Long and dissapears from the argument string that I'm reading in.

I'd appreciate it if someone could help me out on this one.



Thanks.

Replies are listed 'Best First'.
Re: $ variables in command line
by kvale (Monsignor) on Jun 26, 2002 at 21:04 UTC
    Actually, because your argument is in double quotes, the $1 is being interpreted by the shell. If you put your args in single quotes, no interpolation happens:
    ./replace.pl -s '<html(.*)>' -r '<head$1>'
    -Mark
      Thanks,

      but the problem actually lies deeper in my script, for example :

      $test = "hello";
      $s = "(hello)";
      $r = "$1 world";
      $test =~ s/$s/$r/;
      print $test;


      output : hello and not hello world as I would expect.

      Is there any way I could do this ?

        Similar problem, different context. In perl, double quotes causes interpolation, so in
        $r = "$1 world";
        $1 is substituted with whatever was matched in a previous regex. To prevent interpolation, use single quotes.

        That doesn't solve the whole problem, however. Now we need to substitute the strings, including metacharacters, into s///. To interpolate, then substitute, I'll use an eval:
        $s = '(hello)'; $r = '$1 world'; $_ = 'hello'; eval "s/$s/$r/"; print $_;
        A good general rule to follow is to use single quotes if you want the string as is, and use double quotes if you want interpolation.

        -Mark
        You're asking for it to interpolate $1 in $r when you use double-quotes. Don't do this. $1 is undef when you do that, so of course, $r ends up being " world".

        Here's a really crazy example of how to do what you want.
        $test = "hello"; $s = "(hello)"; $r = '"$1 world"'; $test =~ s/$s/eval $r/e; print $test;
        Note that this uses eval, which isn't everyone's thing.
Re: $ variables in command line
by erikharrison (Deacon) on Jun 26, 2002 at 21:05 UTC

    Following regexes will overwrite previously set $1 and friends. Probably your best best would be to tell users that matches aren't stored in $1, $2 etcetera but in an array named @match. Then, after each user defined regex set @match to the values. This will allow them to be persistent (to a degree, based on how many regexes are fed to your script). This can be a bit confusing if there are a lot of usedefined regexes, because your users might wants a greater degree of persistance that one regex. Of course, if that happens, then you probably need a different solution that command line args.

    Cheers,
    Erik

    Light a man a fire, he's warm for a day. Catch a man on fire, and he's warm for the rest of his life. - Terry Pratchet

Re: $ variables in command line
by swiftone (Curate) on Jun 26, 2002 at 21:03 UTC
    I'm guessing it never makes it into the script, and is instead gobbled by the shell. Try escaping the $: ./replace.pl -s "<html(.*)>" -r "<head\$1>"

    Update: yup. perl -e"$foo = 3; print $foo;" demonstrates.

    I see kvale pointed out a solution below.