为什么在这种正则表达式替换中会丢失引号呢?

时间:2018-09-23 09:26:31

标签: regex bash perl

为什么在这种情况下会丢失双引号?

$ cat foo.txt   
This is a \"very good\" text worth AMOUNT dollars    
$ cat full_story.txt   
This is about money:  
STORY  

使用以下命令进行测试:

VAR=$(cat foo.txt)                                                                                         
TOTAL=$(cat full_story.txt)  
echo "$TOTAL" | perl -pe "s/STORY/$VAR/g"  

结果:

This is about money:  
This is a "very good" text worth AMOUNT dollars  

双引号的转义丢失了。我期待:

This is about money:  
This is a \"very good\" text worth AMOUNT dollars  

我如何保存逃生通道?

2 个答案:

答案 0 :(得分:4)

问题在于perl在一个显式替换字符串(不是perl变量中解析反斜杠转义),因此将\"解析为"。例如:

$ echo "A STORY" | perl -pe 's/STORY/\"Hello\"/'
A "Hello"

(请注意,Bash变量$VAR不会变成perl变量$VAR,而是一个常量字符串。)因此,您需要在常量字符串中转义这样的反斜杠:

$ echo "A STORY" | perl -pe 's/STORY/\\"Hello\\"/' 
A \"Hello\"

您可以通过将-s切换到$VAR,将Bash变量perl转换为$VAR变量perl来解决此问题:

echo "$TOTAL" | perl -spe 's/STORY/$VAR/g' -- -VAR="$VAR"

输出

This is about money:  
This is a \"very good\" text worth AMOUNT dollars

说明:

  • -s perl命令行上的用户定义开关启用开关解析。在@ARGV中删除在那里找到的所有开关,并在Perl程序中设置相应的变量。

答案 1 :(得分:3)

您的代码遭受code injection错误。具体来说,您正在尝试从shell生成Perl代码,但失败了。

您将以下内容传递给Perl:

s/STORY/This is a \"very good\" text worth AMOUNT dollars/g

您应该通过以下内容:

s/STORY/This is a \\"very good\\" text worth AMOUNT dollars/g

要正确生成Perl代码,您需要以下内容:

perl -pe's/STORY/'"$( printf %s "$VAR" | sed 's/\W/\\&/g' )"'/'

这会将以下内容传递给Perl(也可以):

s/STORY/This is a \\\"very good\\\" text worth AMOUNT dollars/g

但是,首先避免生成Perl代码要容易得多。不使用STDIN或外部存储将信息传递给Perl的主要方法有三种。

  • 参数

    perl -pe'BEGIN { $VAR = shift(@ARGV) } s/STORY/$VAR/g' -- "$VAR"
    
  • 命令行选项

    在完整程序中,您将使用Getopt::Long,但是perl -s在这里可以正常工作。

    perl -spe's/STORY/$VAR/g' -- -VAR="$VAR"
    
  • 环境变量

    VAR="$VAR" perl -pe's/STORY/$ENV{VAR}/g'