awk、gsub、& 符号和意外扩展

Awk, gsub, ampersands and unexpected expansion

首先,对于可能重复的问题表示歉意。我是 bash 脚本的新手,我什至不知道要搜索的一些关键字。话虽如此,我尽量简化问题描述:

我有一个仅包含这一行的文本文件 (test.txt):

REPLACE

我 运行 以下命令应该用代码变量值 if (A & B).

替换文件的文本(即 REPLACE
code="if (A & B)" ; awk -v var="${code}" '{ gsub(/REPLACE/, var); print }' test.txt

预期输出 我希望 code 变量值按原样打印:

if (A & B)

实际输出 以某种方式将&符号扩展为'REPLACE',即gsub 正则表达式参数:

if (A REPLACE B)

也许我需要转义符号,但不幸的是,code 变量数量超出了我的控制范围,因此我无法手动操作它的值。

仅供参考,awk 版本是 "GNU Awk 4.1.4, API: 1.1 (GNU MPFR 3.1.5, GNU MP 6.1.2)"

谢谢!

& 是许多工具中的反向引用元字符,表示 "the string that matched the regexp you searched for"。如果您尝试使用文字字符串,请使用文字字符串而不是正则表达式和反向引用。

例如:

code="if (A & B)"
awk -v old="REPLACE" -v new="$code" 's=index([=10=],old){[=10=]=substr([=10=],1,s-1) new substr([=10=],s+length(old))} 1' test.txt

尝试对正则表达式和替换进行清理的替代方法很复杂且容易出错,通常不适合胆小的人,请参阅:

您可以对“&”字符进行两次转义,这样您的代码就可以

code="if (A \\& B)" ; awk -v var="${code}" '{ gsub(/REPLACE/, var); print }' test.txt ​

Output:
# code="if (A \\& B)" ; awk -v var="${code}" '{ gsub(/REPLACE/, var); print }' test.txt
if (A & B)
#

请注意,在上面的示例中,您需要转义“\”和“&”字符,这就是为什么它是“\\\&”

如果您不想像上面的示例那样手动操作输入字符串,那么您可以在 awk 代码中使用额外的 'gsub' 来预处理输入字符串,以便在之前添加转义字符运行你的'gsub')如下

code="if (A & B)" ; awk -v var="${code}" '{ gsub("&","\\&", var); gsub(/REPLACE/, var); print }' test.txt

Output:
​​# code="if (A & B)" ; awk -v var="${code}" '{ gsub("&","\\&", var); gsub(/REPLACE/, var); print }' test.txt
​if (A & B)
​#

注意在预处理 gsub 中需要 4 个'\'字符。