![为什么括号“][”需要双重转义“\\”才能防止被 shell 解释?](https://linux22.com/image/885544/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%8B%AC%E5%8F%B7%E2%80%9C%5D%5B%E2%80%9D%E9%9C%80%E8%A6%81%E5%8F%8C%E9%87%8D%E8%BD%AC%E4%B9%89%E2%80%9C%5C%5C%E2%80%9D%E6%89%8D%E8%83%BD%E9%98%B2%E6%AD%A2%E8%A2%AB%20shell%20%E8%A7%A3%E9%87%8A%EF%BC%9F.png)
我使用 'bash' shell 并在文件上执行下面的 'awk' 命令,文件记录以不同字符分隔,例如括号、冒号、圆括号,如下面的示例记录
...(field#13[field#14:]]:filed#18[filed#19)[...
但是,当我使用单个转义符 '\' 来转义“][”时,awk 命令失败,并且我必须双重转义 '\\' 括号才能获得预期结果,它需要如何使用双重转义括号(在 'csh' shell 中也是一样)?
awk -F"[\\[\\]:)(]" '{print $18}' inFile
filed#18
还请注意这一点,我知道我可以像下面这样用双转义符“\\”来转义它们,我只是想知道为什么对于括号这是强制性的?
awk -F"[\\[\\]\\:\\)\\(]" '{print $18}' inFile
filed#18
即使使用单一转义也会发出警告(括号除外),但命令仍然会执行并且结果会出现,谢谢
awk -F '[\\[\\]\:\)\(]' '{print $18}' inFile
awk: warning: escape sequence `\:' treated as plain `:'
awk: warning: escape sequence `\)' treated as plain `)'
awk: warning: escape sequence `\(' treated as plain `('
filed#18
答案1
这里有多个级别的引用/转义。首先,你的FS
正则表达式 ( -F "[\\[\\]\:\)\(]"
) 放在双引号中。这就是发出警告的原因:
$ awk -F"[\\[\\]:)(]" '{print $2}' file
awk: warning: escape sequence `\[' treated as plain `['
awk: warning: escape sequence `\]' treated as plain `]'
awk: fatal: :, [., or [=: /[[]:)(]/
单引号也能起作用:
$ awk -F'[\\[\\]:)(]' '{print $2}' file
field#13
这是因为双引号中的任何内容都首先由 shell 扩展。因此,shell 首先将其扩展\\[
为\[
,然后将其传递给 awk。您可以看到这种情况set -x
:
$ set -x
$ awk -F"[\\[\\]:)(]" '{print $2}' file
+ awk '-F[\[\]:)(]' '{print $2}' file
如上所示,shell 吃了第一个逃逸。所以"
这里根本就不要用。
下一个问题是 awk 本身会解释两次转义。由于可以接受诸如和等-F
特殊转义,因此它会首先尝试将其读取为单个转义字符。由于相同于(不同于 say ,后者不同于 ,因为是换行符),因此它会向您发出警告消息,解释它被视为。\t
\r
\[
\[
[
\n
n
\n
\[
[
因此,您需要第一个转义来转义 本身\
,第二个转义来转义[
。换句话说,在 中\\[
,第一个\
转义了第二个\
,因此awk
最终收到的是\[
。
如果你考虑这样的事情可能会更容易理解:
$ echo -e 'a\tb'
a b ## prints a tab character
$ echo -e 'a\\tb'
a\tb ## prints a literal \t
$ echo -e "a\\tb"
a b ## prints a tab because of the double quotes
$ echo -e "a\\\tb"
a\tb ## 3ple escaping! Prints a literal `\t` again.
上面最后一个例子最能说明问题。由于要回显的字符串在双引号中,因此它首先由 shell 扩展(即吃掉一个\
),然后由shell 扩展echo -e
(即吃掉另一个\
),最后打印为文字\t
。