如何在perl替换中逃避REPLACEMENT?

时间:2013-11-25 00:48:34

标签: regex perl bash replace escaping

如何使用s//运算符完全转义perl替换的REPLACEMENT部分? \Q\E执行工作,如下所示:

对于上下文,当使用perl进行大型递归搜索并替换由bash脚本驱动的操作时,会出现这种情况。这不是一个容易避免的情况。

以此脚本为例:

$ 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/@/\\@}/"

让我们运行它:

$ ./example.sh
EMAIL=user@example.org
+ EMAIL=user@example.org
echo "EMAIL = $EMAIL"
+ echo 'EMAIL = user@example.org'
EMAIL = user@example.org

到目前为止一切顺利。 shell没有破坏任何东西,我们正在回应我们的期望。

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

好的,那次没有引用替换,所以字符串的@example部分被扩展(没有)并且实际上消失了。好的,好吧,让我们和好朋友\Q\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
嗯,那是出乎意料的! \Q\E引用了.,但他们离开@example部分没有转义!这是怎么回事?

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

好的,所以这终于奏效了,但这只是因为我们使用bash模式扩展来进行搜索和替换。它适用于这种特殊情况,因为这是一个电子邮件地址。在更一般的情况下,对于所有可能的替换元字符,这将是非常繁琐的。

再说一遍,在使用s//运算符时,如何完全逃避perl替换的REPLACEMENT部分?可能吗?必须有一个我不知道的伎俩。 =)

解决

ysth的回答建议使用s''',它解决了这个简单的例子,但我无法在我的真实代码中使用它,因为我需要在实际使用中进行反向引用。但是,ysth的回答和TLP的评论均建议使用$ENV{...}。据我所知,到目前为止,这在我的实际用例中是完美的,它必须能够使用反向引用。

以下是上述示例的更新版本。

$ 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/'

运行时它按预期工作:

$ ./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<<

1 个答案:

答案 0 :(得分:4)

\ Q \ E应用于变量插值的结果,因此不能让@example不以这种方式插值。

但你可以使用单引号:

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

或者,如果电子邮件地址可能包含'\\,请让perl从环境中获取$ EMAIL:

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