Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am using perl to colorize a matched string

printf "aaa\n/dev/aaa\nccc\n" | perl -pe "s/($MATCH)/\e[1;31m\1\e[0m/g"

This works well until I try to match a string containing special characters, e.g.

printf "aaa\n/dev/aaa\nccc\n" | perl -pe "s/($MATCH)/\e[1;31m\1\e[0m/g"

The reason is, when bash substitutes $MATCH, perl gets the following expression:

perl -pe "s/(/dev/)/\e[1;31m\1\e[0m/g"

I would need to backslash those / to make it work, i.e.

printf "aaa\n/dev/aaa\nccc\n" | perl -pe "s/($MATCH)/\e[1;31m\1\e[0m/g"    

But I don't know what MATCH will contain. It could be anything, + or (. Is there a way to tell perl to treat the characters literally, not as an expression?


Using solution suggested by Joseph R. gives following error:

printf "aaa\n/dev/aaa\nccc\n" | perl -pe "s/\Q($MATCH)\E/\e[1;31m\1\e[0m/g"
Backslash found where operator expected at -e line 1, near ")\"
(Missing operator before \?)
Having no space between pattern and following word is deprecated at -e line 1.
syntax error at -e line 1, near "s/\Q(/dev/)"
Search pattern not terminated at -e line 1.


now I don't get any error, but there seems to be no match (there is no coloring):

# MATCH=/dev/ ; printf "aaa\n/dev/aaa\nccc\n" | perl -pe 's/(\Q$ENV{MATCH}\E)/\e[1;31m\1\e[0m/g'
share|improve this question
up vote 2 down vote accepted

Yes, you could use Perl's quotemeta operator with single quotes:

export MATCH=...
... | perl -pe 's/(\Q$ENV{MATCH}\E)/...

Anything between \Q and \E (or till the end of the regex if no \E is supplied) is considered as-is with no special meaning attached to metacharacters.


export MATCH=...
... | perl -pe '$sane=quotemeta $ENV{MATCH};s/($sane)/...


Here's how it can be done without export:

printf "aaa\n/dev/aaa\nccc\n" \
 | perl -pe "\$sane=quotemeta q{$MATCH};s/(\$sane)/\e[1;31m\$1\e[0m/g"

Note that your code had a mistake. You can't use a backreference (\1) in the replacement pattern of a s///, you need to use the match variable instead ($1), which I have used as \$1 here, to avoid the shell interpolating $1 because of the soft quotes.

In general, if you're doing a lot of colorizing work with Perl, I would suggest using a module to handle terminal idiosyncrasies for you. Check out Term::ANSIColor for example.

share|improve this answer
I get an error. Please see my updated question. – Martin Vegter May 25 '14 at 22:04
@MartinVegter Sorry, my bad. The quotemeta tricks works with interpolated variables only. Please see the updated answer. – Joseph R. May 25 '14 at 22:14
please see my update2 – Martin Vegter May 25 '14 at 22:20
@MartinVegter As I put in my edit, you need to export MATCH for it to be visible from within the Perl sub-process. In the previous case, the current shell was handling the substitution so it was able to see MATCH without an export. – Joseph R. May 25 '14 at 22:21
@MartinVegter Make sure you're not including the | inside your quotemeta, otherwise it loses its meaning. – Joseph R. Jun 1 '14 at 18:11

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.