遇到一些意想不到但有趣的行为。当我执行一个有点复杂的执行时,我遇到了一种情况,根据我对 Bash 如何处理字符的理解,这种情况不应该发生。
问题的较小示例:
$ arr=( "$(echo '1 && !/==/')" )
-bash: !/=: event not found
这里发生了什么?据我了解,单引号应该强制 Bash 按字面解释所有字符,而不进行任何类型的扩展。
使用 Bash 4.1.2。
编辑:简化的复制问题。
答案1
bash 退出并显示有关不良事件的错误
您已经被可怕的历史替换(!
双引号内的字符)所困扰。您可以使用 禁用它set +H
。顺便说一句,这不会发生在脚本中。
关于分词:您可以使用readarray
(或其别名mapfile
)
readarray -t array < <(df -Ph ...)
答案2
较小的例子(但可能不小美东时间),在 Bash 4.1 中:
$ set -H
$ arr=( "$(echo '1 && !/==/' )" )
bash4.1: !/==/': event not found
$ arr=( $(echo '1 && !/==/' ) ) # no error
$
在 Bash 4.4 中:
$ set -H
$ arr=( "$(echo '1 && !/==/' )" ) # no error
$ arr=( $(echo '1 && !/==/' ) ) # no error
$
那是历史扩展好的。它发生在命令行处理的早期,并且在此之前不会解析整个命令:
历史扩展在读取完整行后立即执行,然后 shell 将其分解为单词,并且对每一行单独执行。
不知道为什么它会这样工作,为什么双引号会产生影响,但这并不是我记得听说过的历史扩展的唯一错误。
set +H
您可以使用、 或关闭历史记录扩展set +o histexpand
,并且默认情况下在脚本中不会启用它。
另请注意,Bash 4.1 已经有 10 多年的历史了,甚至 Bash 4.4(最后一个版本号为 4.x)也是在 2016 年发布的。自 4.1 以来,其他错误也已修复,并添加了有用的功能。