perl, the s/// operator and meta-characters

The other day I was working on adding some extended validation of Nagios confg files.  I have been using Nagios::Object for this job.  What I was specifically testing is in the command object, to see if what was in the command_line was a valid command.  In our configs, we use the $USER1$ through $USER5$ macros extensively.  So I had to do the subsitution before I could test if the command existed.  Here is the subroutine I wrote to do the subsitution:

sub replace_macro {
     my ($cmd) = @_;

     return $cmd if ( $cmd !~ /(\$USER\d+\$)/ );

     my $macro = $1;

     $cmd =~ s/$macro/$macros{$macro}/g;

     return &replace_macro($cmd);
}

I would call it like this:

my $cmd = '$USER1$/check_tcp';
$cmd = &replace_macro($cmd);

The %macros hash had the following entry:

my %macros = (
        '$USER1$' => '/usr/local/nagios/libexec',
        ...
);

But the code was not working. $cmd was still set to $USER1/check_tcp. If I hard coded the $USER1$ in the left hand side of the s/// expression (the PATTERN), it did work. If I changed the macro to be just USER1 it also worked. The perlop man page even talks about evaluating the right hand side of the s/// expression by using the /e or /ee flags, but nothing on the left hand side.

After a few hours of testing, I stumbled across the answer. I had to use the \Q and \E meta-characters to tell perl not to evaluate the left hand side. So the s/// expression became this:

        $cmd =~ s/\Q$macro\E/$macros{$macro}/g;

And now my code works as expected. The \Q is the special meta character to tell perl to disable meta character processing (until the next \E), see perldoc perlre for more information.