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'

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.

  • 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
  • 1
    @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 clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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