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

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

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

arch systemd[908]:

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

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

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

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

然后我用 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

使用 2 个“\”即可:

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

这是我的问题:

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

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

答案1

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

现在,因为您没有引用 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

正如您所看到的,实际运行的命令是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]:

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

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

$ sed 's/\[/:/g' jctl.log
arch systemd:908]:

相关内容