这是GNU Bash中的错误吗?

时间:2011-02-13 16:40:13

标签: bash command-line

我在尝试支持字符串安全性的脚本时发现了这一点:

$ echo '!!'
!!
$ echo "$(echo '!!')"
echo "$(echo 'echo '!!'')"        #<~ the console echoes the line with expanded history here
echo !!                           #<~ the result

在我看来,最内层的引用是单引号的扩展任何,变量,子shell或其他方式,但在这种情况下它会扩展键入的最后一行!!。似乎它不应该这样做。

我问你:这是Bash中的一个错误,是否可以使用带引号的子shell扩展来输出感叹号?

(在Linux中使用Bash 4.1.007)

修改

如果以上不是错误,那么为什么这样做会按预期运行?

$ foo='some value'
$ echo "$(echo 'neither $foo nor `this subshell` should expand here')"
neither $foo nor `this subshell` should expand here

3 个答案:

答案 0 :(得分:2)

我同意。

$ echo "$(echo '!!')"
echo "$(echo 'echo $(echo '!!')')"
echo $(echo !!)

应与

相同
$ echo $(echo '!!')
!!

我无法看到如何根据history expansion documentation解释差异。

历史扩展文档与shell expansions documentation的其他文档完全分开也很奇怪。

zsh回显!!两者,至少在我的设置中。

答案 1 :(得分:1)

这可能是一个错误,但set +H将禁用该错误(默认情况下它在脚本中是关闭的。)

以下是手册页中的相关部分:

  

用双引号括起字符可保留字面值          引号中的所有字符,$,`,\和的除外,          启用历史记录扩展时,!字符$和`保留          它们在双引号内的特殊含义。反斜杠保留了它          只有当后跟下列其中一个字符时才有特殊含义:          $,`,“,或者&lt; newline&gt ;.双引号可以引用          引用前面的反斜杠。如果启用,则扩展历史记录          将被执行,除非!出现在双引号中的是转义          使用反斜杠。之前的反斜杠!没有删除。

  

历史扩展在完整的生产线之后立即执行          读取,在shell将其分解为单词之前。 ......历史扩展是由...引入的          历史扩展人物的外观,这是!通过          默认。只有反斜杠(\)和单引号才能引用历史记录          扩张性。

答案 2 :(得分:1)

如果你将两个刘海放入一个变量中,你将得到你期望的结果(以及更多的字符串安全性)。

(
#set -xv
twobangs='!!'
echo "${twobangs}"
echo "$(echo "${twobangs}")"
echo "$(echo 'echo "${twobangs}"')"
echo "$(echo "echo "${twobangs}"")"
echo "$(echo "echo ""${twobangs}")"
#set -xv
)

在类似的说明中,您有时可以使用shell的内置字符串连接,只需添加一个字符,例如'!'单引号以防止shell解释。

(
set -H
echo "Hello, world"'!'
(sleep 10) & 
#trap "echo exit; kill -TERM $!" EXIT HUP INT QUIT TERM  # troublemaker
#trap "echo exit; kill -TERM $"'!' EXIT HUP INT QUIT TERM
trap "echo exit; kill -TERM $"'!'"; echo killed" EXIT HUP INT QUIT TERM
sleep 5
)