简体   繁体   English

如何使用Perl替换运算符禁用变量插值?

[英]How can I disable variable interpolation with the Perl substitution operator?

I'm trying to replace a particular line in a text file on VMS. 我正在尝试替换VMS上的文本文件中的特定行。 Normally, this is a simple one-liner with Perl. 通常,这是一个简单的Perl单线程。 But I ran into a problem when the replacement side was a symbol containing a VMS path. 但是当替换方是包含VMS路径的符号时,我遇到了问题。 Here is the file and what I tried: 这是文件和我尝试的内容:

Contents of file1.txt: file1.txt的内容:

foo
bar
baz
quux

Attempt to substitute 3rd line: 尝试替换第3行:

$ mysub = "disk$data1:[path.to]file.txt"
$ perl -pe "s/baz/''mysub'/" file1.txt

Yields the following output: 产生以下输出:

foo
bar
disk:[path.to]file.txt
quux

It looks like Perl was overeager and replaced the $data1 part of the path with the contents of a non-existent variable (ie, nothing). 看起来Perl过于苛刻,用一个不存在的变量的内容替换路径的$data1部分(即什么都没有)。 Running with the debugger confirmed that. 运行调试器确认了这一点。 I didn't supply /e , so I thought Perl should just replace the text as-is. 我没有提供/e ,所以我认为Perl应该直接替换文本。 Is there a way to get Perl to do that? 有没有办法让Perl这样做?

(Also note that I can reproduce similar behavior at the linux command line.) (另请注意,我可以在linux命令行中重现类似的行为。)

As ruakh discovered when reading my comment, the problem of perl interpolation can be solved by accessing the %ENV hash, rather than using a shell variable: 正如Ruakh在阅读我的评论时发现的那样,perl插值问题可以通过访问%ENV哈希来解决,而不是使用shell变量:

perl -pwe "s/baz/$ENV{mysub}/" file1.txt

Added -w because I do not believe in not using warnings even in one-liners. 添加-w因为我不相信即使在单行中也不使用warnings

With just the right mix of quotes and double quotes you can get there: 只需正确混合引号和双引号,您就可以到达:

We create a tight concatenation of "string" + 'substitute symbol' + "string". 我们创建了“string”+“替换符号”+“string”的紧密连接。 The two double quoted strings contain single quotes for the substitute. 两个双引号字符串包含替换的单引号。 Contrived... but it works. Contrived ......但它确实有效。

$ perl -pe "s'baz'"'mysub'"'" file1.txt

That's a DCL level solution. 这是一个DCL级别的解决方案。

For a Perl solution, use the q() operator for a non-interpolated string and execute that. 对于Perl解决方案,使用q()运算符作为非插值字符串并执行它。 Stuff the symbol into the parens using simple DCL substitution. 使用简单的DCL替换将符号填入parens。 This is my favorite because it (almost) makes sense to me and does not get too confusing with quotes. 这是我的最爱,因为它(几乎)对我有意义,并且不会引起混淆。

$ perl -pe "s/baz/q(''mysub')/e" file1.txt

Haven't even seen a VMS system in decades, but ... escape your sigil? 几十年来甚至没有见过VMS系统,但是......逃避你的印记?

$ mysub = "disk\$data1:[path.to]file.txt"

or maybe 或者可能

$ mysub = "disk\\$data1:[path.to]file.txt"

?

For sh or a derivative, I'd use 对于sh或衍生物,我会使用

perl -pe'BEGIN { $r = shift(@ARGV) } s/baz/$r/' "$mysub" file1.txt

Otherwise, you have to somehow covert the value of mysub into a Perl string literal. 否则,你必须以某种方式将mysub的值转换为Perl字符串文字。 That would be more complicated. 那会更复杂。 Find the equivalent for your shell. 找到你的shell的等价物。

Edit by OP: 由OP编辑:

Yes, this works. 是的,这很有效。 The VMS equivalent is VMS等价物是

perl -pe "BEGIN { $r = shift(@ARGV) } s/baz/$r/" 'mysub' file1.txt

Use sed. 使用sed。

Sed won't try to interpolate $data1 as a variable, so you should get what you want. Sed不会尝试将$data1插入为变量,因此您应该得到您想要的。

$ sed -e "s/baz/''mysub'/" file1.txt

You have to escape the $ with \\$ . 你必须逃离$\\$ Otherwise Perl sees a variable reference and replaces the string $data1 with the content of $data1 before the regular expression is evaluated. 否则,Perl中看到一个变量引用,并替换字符串$data1与内容$data1正则表达式求值之前。 As you didn't define $data1 it is, of course, empty. 由于你没有定义$data1它当然是空的。

You can use the following code : 您可以使用以下代码:

$ mysub='disk\$data1:[path.to]file.txt'
$ perl -pe 's/baz/'$mysub'/' FILE
foo
bar
disk$data1:[path.to]file.txt
quux

You could try using a logical name instead of a DCL symbol: 您可以尝试使用逻辑名称而不是DCL符号:

$ define mysub "disk$data1:[path.to]file.txt"
$ $ perl -pe "s/baz/mysub/" file1.txt

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

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