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


25

请查看以下命令:

$ 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出现错误吗?

Answers:


31

!是Bash中默认的历史记录扩展字符,请参见Bash手册页中的“ HISTORY EXPANSION”部分

  • 如果将!括在单引号中,则不会进行历史记录扩展,例如

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

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

    echo "SYNC TIME!"

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


4
可以通过添加到.bashrc行中来解决此不良行为set +H。注意,!在脚本编写中已经不是特别的了。将其视为特殊内容会破坏许多符合标准的脚本。在交互式Shell中,它仅被视为“特殊”,并且只有在您修复它之前,默认情况下才被视为。:-)
R.,

15

因为在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\!

6
echo Hello world!确实有效-历史扩展不是由空格触发的;-)(啊,好的例子...)
Rmano 2014年

1
不过,最好不要使用感叹号,而要使用空格。
Ehtesh Choudhury 2014年

1
@Rmano我更愿意明确地这样说,而不是指导我改变行为的可能性
Braiam 2014年

!保留字bash,如POSIX还声明。但是我很确定它的地位它在历史扩展中的作用完全无关,并且与它在双引号中的处理无关。!是保留字,因为它会否定命令/管道的退出状态,因此不能用作命令。没有其他的保留字是在一个特殊的"-quoted方面,虽然$不是保留字,但特殊对待。
伊利亚·卡根
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.