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

DK *_*ose 26 bash

请查看这些命令:

$ notify-send SYNC TIME!
$ notify-send 'SYNC TIME!'
$ notify-send "SYNC TIME!"
bash: !": event not found
$
Run Code Online (Sandbox Code Playgroud)

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

$ echo SYNC TIME!
SYNC TIME!
$ echo 'SYNC TIME!'
SYNC TIME!
$ echo "SYNC TIME!"
bash: !": event not found
$
Run Code Online (Sandbox Code Playgroud)

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

这里有更多问题(虽然我不打算使用它): bothnotify-send "SYNC!TIME"echo "SYNC!TIME"give bash: !TIME": event not found

但两者notify-sendecho用工作"SYNC! TIME"

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

Flo*_*sch 33

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

  • 这种不当行为可以通过在你的 `.bashrc` 中添加一行 `set +H` 来解决。请注意,`!` 在脚本中已经是非特殊的;将其视为特殊的会破坏许多符合标准的脚本。它仅在交互式 shell 中被视为“特殊”,并且仅在默认情况下才会被修复,直到您修复它。:-) (4认同)

ter*_*don 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.
Run Code Online (Sandbox Code Playgroud)

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

$ echo foo
foo
$ !e
echo foo
foo
Run Code Online (Sandbox Code Playgroud)

所述!激活历史扩展,其匹配从第一个开始命令e,其是先前运行echo foo中,然后再次运行。因此,当您编写 时"SYNC TIME!",bash 看到!", 搜索历史记录以查找以 开头的命令",失败并抱怨它。例如,您可以通过运行获得相同的错误!nocommandstartswiththis

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

echo 'Hello world!'
echo Hello world\!
Run Code Online (Sandbox Code Playgroud)

  • `echo Hello world!` 确实有效 --- 历史扩展不是由空白触发的 ;-) (啊,很好的角落案例......) (6认同)