我在尝试支持字符串安全性的脚本时发现了这一点:
$ 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
答案 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
)