How to escape the REPLACEMENT in a perl substitution?

bash, escaping, perl, regex, replace

Solution

\Q\E are applied to the results of variable interpolation, so you can't keep @example from interpolating that way.

But you can use single quotes:

#!/bin/bash
set -v -x
EMAIL=user@example.org
echo "Email address: here" | perl -p -e "s'here'$EMAIL'"

or, if the email address may contain `'` or `\\`, let perl get $EMAIL from the environment:

export EMAIL=user@example.org
echo "Email address: here" | perl -p -e 's/here/$ENV{EMAIL}/'

Problem

How do you completely escape the REPLACEMENT part of a perl subsitution with the `s//` operator? `\Q` and `\E` do not work as, shown below: For context, this comes up when using perl to do big recursive search and replace operations driven from a bash script. This is not an easily avoidable situation. Take this script for example: ``` $ cat example.sh #!/bin/bash set -v -x EMAIL=user@example.org echo "EMAIL = $EMAIL" echo "Email address: here" | perl -p -e "s/here/$EMAIL/" echo "Email address: here" | perl -p -e "s/here/\\Q$EMAIL\\E/" echo "Email address: here" | perl -p -e "s/here/${EMAIL/@/\\@}/" ``` Let's run it: ``` $ ./example.sh EMAIL=user@example.org + EMAIL=user@example.org echo "EMAIL = $EMAIL" + echo 'EMAIL = user@example.org' EMAIL = user@example.org ``` So far so good. The shell isn't mangling anything and we are echoing what we expect. ``` echo "Email address: here" | perl -p -e "s/here/$EMAIL/" + echo 'Email address: here' + perl -p -e s/here/user@example.org/ Email address: user.org ``` Okay, that time the replacement wasn't quoted, so the `@example` part of the string got expanded (to nothing) and effectively disappeared. Okay, fine, let's escape it with our good friends `\Q` and `\E`: ``` echo "Email address: here" | perl -p -e "s/here/\\Q$EMAIL\\E/" + echo 'Email address: here' + perl -p -e 's/here/\Quser@example.org\E/' Email address: user\.org ``` Well, that was unexpected! `\Q` and `\E` quoted the `.`, but they left the `@example` part unescaped! What is going on here? ``` echo "Email address: here" | perl -p -e "s/here/${EMAIL/@/\\@}/" + echo 'Email address: here' + perl -p -e 's/here/user\@example.org/' Email address: user@example.org ``` Okay, so this finally worked, but only because we used bash pattern expansion to do a search and replace. It worked in this particular case because this was an e-mail address. This would be incredibly tedious to do for all possible replacement metacharacters in a more general case. So again, how do you escape the REPLACEMENT part of a perl subsitution completely when using the `s//` operator? Is it possible? There has to be a trick I'm missing. =) SOLVED ysth's answer suggested using `s'''`, which solves this simple example, but I couldn't use that in my real code, because I needed backreferences in my real use caes. However, ysth's answer and TLP's comment both proposed using `$ENV{...}`. As far as I can tell, this works perfectly so far in my real use cases, which must be able to use back-references. Here is an updated version of the example shown above. ``` $ cat example-new.sh #!/bin/bash set -v -x EMAIL=user@example.org # Don't touch my delimiters! echo "Email address goes >>>>>>here<<" | perl -p -e 's/(>+)here(<+)/$1$ENV{EMAIL}$2/' ``` It works as expected when running it: ``` $ ./example-new.sh EMAIL=user@example.org + EMAIL=user@example.org # Don't touch my delimiters! echo "Email address goes >>>>>>here<<" | perl -p -e 's/(>+)here(<+)/$1$ENV{EMAIL}$2/' + echo 'Email address goes >>>>>>here<<' + perl -p -e 's/(>+)here(<+)/$1$ENV{EMAIL}$2/' Email address goes >>>>>>user@example.org<< ```

Original source