假设我有一个包含文本
foo_bar_baz
的文件,并且我想将其替换为 foo_bar_var
(其中 var
是 bash 变量的值):
第一次尝试:
#!/bin/bash
$ key=1234
$ echo "foo_bar_baz" > testfile
$ perl -pi -e "s/(foo_)(bar_).*/\1\2 $key/" testfile
$ cat testfile
foo_bar_ 1234
所以,我只需要去掉
1234
之前的空格即可。显而易见的答案是
$ perl -pi -e "s/(foo_)(bar_).*/\1\2$key/" testfile
...但这行不通。替换中包含八进制字符
\212
。我该如何解决?八进制问题简要介绍了here,但我似乎错过了答案。该文档指出“只有在其前面至少有 10 个左括号时,Perl 才会通过解释为反向引用来解决这种歧义”,但这里显然不是这种情况。此外,使用 \g2
或 \g{2}
并不能解决问题。
我使用的是 Perl 5.34.0,bash 5.1.16。
编辑
澄清这是 bash 脚本中的一行,所以我不能使用单引号代替双引号,并且我不能用
$
替换,因为这些是 bash 变量。
替换文本应使用
$1
代替 \1
来表示捕获组的内容。与任何其他参数扩展一样,您可以使用 {...}
分隔参数名称。
perl -pi -e 's/(foo_)(bar_).*/$1${2}1234/' testfile
(请注意使用单引号来简化对
$1
和 $2
的转义,以避免在 Perl 看到要执行的脚本之前对每个内容进行 shell 插值。)
经过大量随机输入后,我想我找到了一个“答案”,但我不喜欢它。问题中的原始代码有效 if 您可以保证要替换的变量的第一个字符不是数字(因此
key=abcd
有效,但 key=1bcd
无效)。
如果您事先不知道变量的第一个字符是什么,那么您必须导出并读取变量:
#!/bin/bash
echo "foo_bar_baz" > testfile
export key=1235
perl -pi -e 's/(foo_)(bar_).*/$1$2$ENV{key}/' testfile
cat testfile
这似乎与here的文档完全相反,因为这里只有2个捕获组,所以不存在歧义的可能性(
\21234
不可能是一个捕获组)。
这让我觉得在 bash 脚本中使用 Perl 语句进行替换并不是一个好主意。我已经发现我的一个旧脚本没有用数字进行测试并且失败了。将来,我想我将使用 bash-native 替换。