什么是“-bash: !”:事件未找到”

Max*_*ler 151 scripting linux shell bash

尝试在 bash shell 下执行以下命令 echo "Reboot your instance!"

在我的安装中:

root@domU-12-31-39-04-11-83:/usr/local/bin# bash --version
GNU bash, version 4.1.5(1)-release (i686-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
root@domU-12-31-39-04-11-83:/usr/local/bin# uname -a
Linux domU-12-31-39-04-11-83 2.6.35-22-virtual #35-Ubuntu SMP Sat Oct 16 23:57:40 UTC 2010 i686 GNU/Linux
root@domU-12-31-39-04-11-83:/usr/local/bin# echo "Reboot your instance!"
-bash: !": event not found
Run Code Online (Sandbox Code Playgroud)

谁能解释一下什么是“bash事件”?我以前从未听说过这个概念。另外,我应该如何输出“!” 在句子的末尾?

Mad*_*ter 134

!是 bash 的特殊字符,用于引用之前的命令;例如,

!rm
Run Code Online (Sandbox Code Playgroud)

将调用并执行以字符串“rm”开头的最后一个命令,并且

!rm:p
Run Code Online (Sandbox Code Playgroud)

将调用但不执行以字符串“rm”开头的最后一个命令。bash 将感叹号解释echo "reboot your instance!"为“在此处替换以紧跟在感叹号之后的字符开头的最后一个命令”,并向您抱怨说它在您的历史记录中找不到以单个开头的事件(命令)双引号。

尝试

echo reboot your instance\!
Run Code Online (Sandbox Code Playgroud)

保护(转义)感叹号免受 bash 的攻击。

  • 这很糟糕。如果我没有避开感叹号,bash 就会大发雷霆。如果我 *do* 转义它,反斜杠将包含在最终字符串中。你为什么要这样做,巴什!!(http://pastebin.com/g4PYv56A) (6认同)
  • 简单的解决方案是同时使用单引号和双引号:echo -e "Text\nReeboot"'!' (2认同)
  • @Hubro 公平地说,我不确定这都是 bash 的错。通过使用 ruby​​ 将东西提供给 bash,你有一些复杂的问题,我不清楚 ruby​​ 在剥离或加强转义字符中扮演什么角色。 (2认同)
  • `echo '重启你的实例!'` 也能工作,因为 `'` 之间的字符让 shell 逐字解释它们。 (2认同)

Den*_*son 84

您可以使用 关闭历史替换set +H

  • @PunkyGuy:我不知道它背后的历史(双关语),但 Unix 选项通常以连字符(或减号)开头,而 `+` 恰恰相反。 (10认同)
  • 你知道语法背后的原因吗?这似乎真的违反直觉。你会认为你会输入 `+H` 来启用某些东西,而输入 `-H` 来禁用某些东西。 (3认同)
  • 虽然这个问题正确地解决了bash,因为这就是问题所问的,我想我会提到在“zsh”中,近似等效的是“set -K”或“setopt NO_BANG_HIST”(大写和下划线可选,但这就是它的方式显示在文档中,因此以这种方式引用它,以防人们需要更多详细信息)。 (3认同)

Sma*_*ger 32

要解决您原来的问题,请尝试使用单引号,而不是双引号。对于后者,bash 将在将结果传递给命令(在这种情况下为 echo)之前尝试扩展某些字符。使用单引号,bash 传递整个字符串,不变。

!在命令中用于引用命令行历史记录。请参阅:http : //tldp.org/LDP/abs/html/abs-guide.html#HISTCOMMANDS获取完整集。在上面的示例中,bash 试图!"在 echo 查看之前扩展为对事件的引用,因此出现错误。

请注意,在脚本中,所有历史命令都被禁用,因为它们只在交互式 shell 中有意义。

我唯一经常使用的就是!$. 它扩展到上一个命令的最后一个参数。在某些地方,这是一个有用的速记。

  • `!!` 填写完整的最后输入的命令非常有用;特别是,`sudo !!` 或 `pfexec !!` (6认同)
  • 我还发现 sudo 和 pfexec 是不错的实用程序,但无需如此热情。 (6认同)

小智 9

只需在!和之间留一个空格"就可以了。

  • 这是有效的,因为 Bash 只处理 ! 如果后跟非空白字符,则作为特殊字符。但是,它还会为您的输出添加一个额外的空白,因此可能并不总是需要... (4认同)
  • 您能否解释一下您的解决方案为何有效? (3认同)

小智 6

是的, !是 bash 的特殊字符,用于引用之前的命令。

您可以处理这种情况的几种方法

以下将按原样输出字符串

echo 'Reboot your instance!'
Run Code Online (Sandbox Code Playgroud)

以下将执行命令并连接字符串

echo 'escaping #'" adding `which python` to the string"
echo '#!'`which python`
Run Code Online (Sandbox Code Playgroud)


Roe*_*aar 5

您还可以添加

histchars=  
Run Code Online (Sandbox Code Playgroud)

./bash_profile(或在命令行上将其用作一次性)

禁用!“特殊历史字符”,或将其设置为其他字符。

警告; ~例如,当您将其设置为其他字符串时,某些事情可能会中断。

看:

$ echo "!test"
-bash: !test: event not found
$ histchars=
$ echo "!test"
!test
$ histchars=7
$ echo "7test"
-bash: 7test: event not found
$ histchars=
$ histchars=~
$ histchars=
hars=hars=~     # odd output
$ ~/test
-bash: /test: event not found
Run Code Online (Sandbox Code Playgroud)