为什么我必须在 sed 中对特定字符进行双重转义?

kry*_*ysk 2 sed

这只是一个显示问题的测试文件。原来的部分看起来像这样:

arch systemd[908]:
Run Code Online (Sandbox Code Playgroud)

现在我可以用“:”字符替换右括号

krys@archeos:~/test]$ cat jctl.log | cut -d " " -f 4,5 | head | sed s/]/:/g
arch systemd[908::
Run Code Online (Sandbox Code Playgroud)

当我尝试更换开口支架时,它不起作用:

krys@archeos:~/test]$ cat jctl.log | cut -d " " -f 4,5 | head | sed s/[/:/g
sed: -e expression #1, char 7: unterminated `s' command
Run Code Online (Sandbox Code Playgroud)

然后我用 1 \ 字符转义了“[”,但它仍然不起作用

krys@archeos:~/test]$ cat jctl.log | cut -d " " -f 4,5 | head | sed s/[/:/g
sed: -e expression #1, char 7: unterminated `s' command
Run Code Online (Sandbox Code Playgroud)

使用 2 个“\”即可:

krys@archeos:~/test]$ cat jctl.log | cut -d " " -f 4,5 | head | sed s/\\[/:/g
arch systemd:908]:
Run Code Online (Sandbox Code Playgroud)

这是我的问题:

  • 为什么它适用于右括号但不适用于左括号?sed 或 bash 读取此内容的方式有何不同?
  • 为什么有必要对左括号进行双重转义,而它与右括号配合得很好,根本不需要转义它?

我只是想了解这一点。我现在知道如何做到这一点,但我对不知道细节感到不满意。

ter*_*don 5

这是因为您没有引用 sed 表达式(坏主意,养成将sed命令放在单引号中的习惯)。您需要转义的原因[是因为[它在正则表达式中具有特殊含义,它打开一个字符类(例如,[abc]将匹配ab或 之一c)。您不需要转义,]因为 sed 足够聪明,知道在这种情况下,]不会关闭字符类,因为没有前面[可以关闭。

现在,因为您没有引用 sed 表达式,这意味着 shell 将在将其传递给之前尝试解释它sed。因此,shell 会看到您的\[,并使用转义符将其未转义的传递给 sed。您可以通过以下方式查看此操作的实际效果set -x

$ set -x
$ sed s/\[/:/g jctl.log
+ sed 's/[/:/g' jctl.log
sed: -e expression #1, char 7: unterminated `s' command
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,实际运行的命令是sed 's/[/:/g' jctl.log而不是sed 's/\[/:/g' jctl.log:shell 已经消耗了转义符。然后会失败,因为 sed 正在寻找结束符],但没有找到,因此将整个字符串视为/:/g字符类的内容,因此失败,因为它找不到命令的结尾s///

添加第二级转义允许 shell 消耗一级转义,然后仍然将转义传递给[sed:

$ sed s/\\[/:/g jctl.log
+ sed 's/\[/:/g' jctl.log
arch systemd:908]:
Run Code Online (Sandbox Code Playgroud)

您可以在上面的输出中看到 sed 是\[now 给出的,而不是[

如果您始终引用 sed 命令,所有这些问题都会消失:

$ sed 's/\[/:/g' jctl.log
arch systemd:908]:
Run Code Online (Sandbox Code Playgroud)