我用来perl
给匹配的字符串着色
MATCH=aaa
printf "aaa\n/dev/aaa\nccc\n" | perl -pe "s/($MATCH)/\e[1;31m\1\e[0m/g"
这很有效,直到我尝试匹配包含特殊字符的字符串,例如
MATCH=/dev/
printf "aaa\n/dev/aaa\nccc\n" | perl -pe "s/($MATCH)/\e[1;31m\1\e[0m/g"
原因是,当bash
替换时$MATCH
,perl 得到以下表达式:
perl -pe "s/(/dev/)/\e[1;31m\1\e[0m/g"
我需要反斜杠才能/
使其工作,即
MATCH=\/dev\/
printf "aaa\n/dev/aaa\nccc\n" | perl -pe "s/($MATCH)/\e[1;31m\1\e[0m/g"
但我不知道MATCH
会包含什么。它可以是任何东西,+
或者(
。有没有办法告诉我们perl
按字面意思对待字符,而不是作为表达式?
更新:
使用建议的解决方案Joseph R.
会出现以下错误:
MATCH=/dev/
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.
更新2:
现在我没有收到任何错误,但似乎没有匹配(没有着色):
# MATCH=/dev/ ; printf "aaa\n/dev/aaa\nccc\n" | perl -pe 's/(\Q$ENV{MATCH}\E)/\e[1;31m\1\e[0m/g'
aaa
/dev/aaa
ccc
答案1
quotemeta
是的,您可以使用带单引号的 Perl运算符:
export MATCH=...
... | perl -pe 's/(\Q$ENV{MATCH}\E)/...
\Q
和之间的任何内容\E
(如果没有提供,则直到正则表达式末尾\E
)都被视为原样,元字符没有附加任何特殊含义。
等效地:
export MATCH=...
... | perl -pe '$sane=quotemeta $ENV{MATCH};s/($sane)/...
更新
这是如何做到的没有export
:
MATCH=/dev/
printf "aaa\n/dev/aaa\nccc\n" \
| perl -pe "\$sane=quotemeta q{$MATCH};s/(\$sane)/\e[1;31m\$1\e[0m/g"
请注意,您的代码有一个错误。您不能\1
在 a 的替换模式中使用反向引用 ( ) s///
,您需要使用匹配变量 ( $1
) (我在这里使用的)\$1
,以避免 shell$1
由于软引号而进行插值。
一般来说,如果您使用 Perl 进行大量着色工作,我建议您使用一个模块来处理终端特性。查看术语::ANSIColor例如。