【问题标题】:How to escape the REPLACEMENT in a perl substitution?如何在 perl 替换中转义 REPLACEMENT?
【发布时间】:2013-12-09 14:14:23
【问题描述】:

如何使用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<<

【问题讨论】:

  • 你到底想在这里做什么:${EMAIL/@/\\@}?
  • @TLP 是用于替换变量扩展的 bash 语法。
  • 也许您应该尝试将s/here/$EMAIL/ 替换为s/here/\$ENV{EMAIL}/。这就是您在 Perl 中访问环境变量的方式。和/或还将' 更改为",这样您也许可以删除反斜杠。
  • @TLP 你的评论和 ysth 的回答都建议 $ENV{...} 这是解决这个问题的好方法!
  • 确实如此。您可以使用环视断言来代替使用字符串捕获:s/(?&lt;=&lt;)here(?=&lt;)/$ENV{EMAIL}/,这样可以省去使用$1 等的麻烦。

标签: regex perl bash replace escaping


【解决方案1】:

\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}/'

【讨论】:

  • 单引号的方式在某些实际情况下不起作用,因为替换也使用$1等,但$ENV{...}的方法看起来可以完美地工作。
  • 这不适用于$1;你能用你的预期输出来举例说明这种用法吗?
  • 我用解决方案部分更新了我的问题,以显示您的$ENV{...} 建议如何满足我对$1 的需求。
  • 啊,我以为你的意思是 $EMAIL 中的 1 美元
猜你喜欢
  • 1970-01-01
  • 2016-08-03
  • 1970-01-01
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
  • 2011-07-10
  • 1970-01-01
  • 2013-12-31
相关资源
最近更新 更多