简体   繁体   English

如何在Perl替代中转义REPLACEMENT?

[英]How to escape the REPLACEMENT in a perl substitution?

How do you completely escape the REPLACEMENT part of a perl subsitution with the s// operator? 如何用s//运算符完全摆脱perl替换的REPLACEMENT部分? \\Q and \\E do not work as, shown below: \\Q\\E 工作的,如下图所示:

For context, this comes up when using perl to do big recursive search and replace operations driven from a bash script. 对于上下文,这在使用perl进行大型递归搜索并替换bash脚本驱动的操作时出现。 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. 好的,那个时候没有引用替换,所以字符串的@example部分扩展了(什么也没有)并有效地消失了。 Okay, fine, let's escape it with our good friends \\Q and \\E : 好吧,好吧,让我们与我们的好朋友\\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

Well, that was unexpected! 好吧,那是出乎意料的! \\Q and \\E quoted the . \\Q\\E引用. , but they left the @example part unescaped! ,但他们未保留@example部分! 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. 好的,这终于奏效了,但这只是因为我们使用了bash模式扩展来进行搜索和替换。 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? 再说一遍,当使用s//运算符时,如何完全避开perl替换的REPLACEMENT部分? 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. ysth的答案建议使用s'''来解决这个简单的示例,但是我不能在我的实际代码中使用它,因为在我的实际使用caes中需要反向引用。 However, ysth's answer and TLP's comment both proposed using $ENV{...} . 但是,ysth的答案和TLP的评论都建议使用$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<<

\\Q\\E are applied to the results of variable interpolation, so you can't keep @example from interpolating that way. \\ Q \\ E应用于变量插值的结果,因此您不能阻止@example那样插值。

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: 或者,如果电子邮件地址可能包含'\\\\ ,则让perl从环境中获取$ EMAIL:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM