为什么双引号内的感叹号会导致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错误?

! 是Bash中的默认历史记录扩展字符,请参阅Bash联机帮助页中的“HISTORY EXPANSION”部分

  • 历史扩张如果不发生! 用单引号括起来,如

     notify-send 'SYNC TIME!' 
  • 历史扩张如果不发生! 后跟一个空格,制表符,换行符,回车符或= ,如下所示

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

     echo "SYNC TIME!" 

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

因为在bash中! 是一个保留字(OK,character),它在不同的上下文中具有特殊含义。 在这种特殊情况下,你在历史搜索中与其重要性相悖。 来自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\!