当前位置: 首页>>技术教程>>正文


为什么双引号中的感叹号会导致Bash错误?

问题描述

请查看以下命令:

$ notify-send SYNC TIME!
$ notify-send 'SYNC TIME!'
$ notify-send "SYNC TIME!"
bash: !": event not found
$

前两个命令按预期产生通知气泡。第三个给出显示的错误。

$ echo SYNC TIME!
SYNC TIME!
$ echo 'SYNC TIME!'
SYNC TIME!
$ echo "SYNC TIME!"
bash: !": event not found
$

同样在这里,echo适用于前两个命令,但不适用于第三个命令。

这里还有更多问题(尽管我不打算使用它):notify-send "SYNC!TIME"echo "SYNC!TIME"都给出bash: !TIME": event not found

但是notify-sendecho均可与"SYNC! TIME"一起使用

有人可以解释为什么出现bash: !": event not found错误吗?

最佳办法

!是Bas​​h中的默认历史记录扩展字符,请参阅Bash manpage中的”HISTORY EXPANSION”部分

  • 如果!用单引号引起来,则不会进行历史扩展,例如

    notify-send 'SYNC TIME!'
    
  • 如果!后跟一个空格,制表符,换行符,回车符或=,则不会进行历史记录扩展,如

    notify-send SYNC TIME!
    
  • 历史扩展确实发生在

    echo "SYNC TIME!"
    

    因此,如果您的历史记录中没有以"开头的命令,则会出现错误

次佳办法

因为在bash中,!是保留字(OK,字符),所以它在不同的上下文中具有特殊的含义。在这种情况下,您将无法理解其在历史搜索中的重要性。从man bash

   History expansions introduce words from the history list into the input
   stream, making it easy to repeat commands, insert the  arguments  to  a
   previous command into the current input line, or fix errors in previous
   commands quickly.

  [...]

   History expansions are introduced by
   the appearance of the  history  expansion  character,  which  is  !  by
   default.   Only  backslash  (\) and single quotes can quote the history
   expansion character.

基本上,这意味着bash将在!之后获取字符,并在历史记录中搜索它发现的以这些字符开头的第一个命令。演示比解释容易:

$ echo foo
foo
$ !e
echo foo
foo

!已激活的历史记录扩展,与第一个以e开始的命令匹配,该命令是先前运行的echo foo,然后又运行了。因此,当您编写"SYNC TIME!"时,bash看到了!",在历史记录中搜索了以"开头的命令,但失败并提出了抱怨。您可以通过运行例如!nocommandstartswiththis来获得相同的错误。

要打印感叹号,您需要通过以下两种方式之一对其进行转义:

echo 'Hello world!'
echo Hello world\!

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/11618.html,未经允许,请勿转载。