Regex 为什么在这个正则表达式替换中引号的转义丢失了?
为什么在这种情况下双引号的转义会丢失Regex 为什么在这个正则表达式替换中引号的转义丢失了?,regex,bash,perl,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)
$ 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
我怎样才能保存这些逃犯 问题在于
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\"
您可以通过使用切换到perl
将Bash变量$VAR
转换为perl
变量$VAR
来解决此问题,如下所示:
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
中删除,并在Perl程序中设置相应的变量@ARGV
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 -pe's/STORY/'"$( printf %s "$VAR" | sed 's/\W/\\&/g' )"'/'
要正确生成Perl代码,您需要以下内容:
s/STORY/This is a \\"very good\\" text worth AMOUNT dollars/g
perl -pe's/STORY/'"$( printf %s "$VAR" | sed 's/\W/\\&/g' )"'/'
这会将以下内容传递给Perl(这也很好):
不过,首先避免生成Perl代码要简单得多。有三种主要方法可以在不使用STDIN或外部存储的情况下将信息传递给Perl
- 论据
perl -pe'BEGIN { $VAR = shift(@ARGV) } s/STORY/$VAR/g' -- "$VAR"
- 命令行选项
在一个完整的程序中,您可以使用,但在这里会做得很好
perl -spe's/STORY/$VAR/g' -- -VAR="$VAR"
- 环境变量
VAR="$VAR" perl -pe's/STORY/$ENV{VAR}/g'
foo.txt
中的文本,比如“这是…”
@keithpjolley:1)引用这是…
仍然会删除转义。这也不是我想要的,因为我不知道那句话引用了什么2)做双转义可以解决这个问题,但我宁愿不做,因为副本有转义already@keithpjolley:+1尽管如此,双转义仍然有效。我想理解为什么这种方法不起作用,这只是用光了我头脑中最后一点perl知识:echo“$TOTAL”| perl-pe'$v=q{'$VAR'};s/STORY/$v/g'
。我相信有不同的方法可以做到这一点。另一种解决方法是说:echo“$TOTAL”| perl-pe“s'STORY'$VAR'g”
,因此替换的内容可以被逐字解析。@tshiono谢谢,观察得很好。我已将你的建议编辑成我的答案。@HåkonHægland:非常有用!在--VAR=“$VAR”
中,为什么需要VAR
前面的破折号?也就是说,为什么它不是--VAR=“$VAR”
?我无法从你粘贴的文档中理解它应该是这样的是的,我也认为文档在thant点不是很清楚。有关更多信息,请参见答案。因此,我认为需要用破折号将-VAR
和其他用户开关与普通的perl
选项分开。我对它进行了一点测试,您甚至可以通过添加另一个--
的实例来混合普通参数(@ARGV
),如下所示:perl-sE'say':ARGV=“,join”|“,@ARGV;说“VAR=$VAR”--VAR=ss--1 2 3
@ikegami抓得好!因此,第一种使用-s
的方法比第二种不使用-s
的方法更正确?太棒了!一个问题:基本上,如果我在文本中有“非常好”
,所有这些都是不必要的?所以你建议放一段Perl代码——甚至不是一个完整的标记在您的数据文件中。这是自找麻烦,这是个可怕的主意。我已经说过以下几次了,但它似乎没有被理解:不要试图从shell生成Perl代码!等待你的意思是“非常好”是perl代码吗?啊,我现在明白了。我不明白这取决于VAR1
是一个正则表达式模式,还是一个字面上匹配的文本字符串。很可能是后者,所以您刚刚引入了一个新的代码注入。您需要将文本转换为正则表达式:perl-pe的/\Q$ENV{VAR1}/$ENV{VAR2}/g'
通过切换到双引号,您使$
成为shell的特殊部分。