Bash 解释单引号内的特殊字符

Bash 解释单引号内的特殊字符

遇到一些意想不到但有趣的行为。当我执行一个有点复杂的执行时,我遇到了一种情况,根据我对 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 以来,其他错误也已修复,并添加了有用的功能。

相关内容