多行双引号字符串会触发后续单引号命令的历史记录扩展

时间:2016-06-14 09:36:41

标签: bash gnu command-substitution

我使用的是GNU bash,版本4.3.11。

说我想在文件上打印唯一的行。我正在使用这种方法,它适用于文件:

$ cat a
9
10
9
11
$ awk '!seen[$0]++' a
9
10
11

但是,如果我从stdin获取输入,在多行中使用双引号并输入到awk,则会失败:

$ echo "9
> 10
> 9
> 11" | awk '!seen[$0]++'
bash: !seen[$0]++': event not found

也就是说,bash尝试扩展命令seen,这当然不知道,因为它是一个变量名。但它不应该发生,因为命令放在单引号内。

echo单引号,多行输入效果很好:

$ echo '9
> 10
> 9
> 11' | awk '!seen[$0]++'
9
10
11

有趣的是,它也适用于双引号的单行输入:

$ printf "9\n10\n9\n11" | awk '!seen[$0]++'
9
10
11

我想知道为什么Bash试图扩展历史,如果它发生在多行输入后,即使命令本身使用单引号。

其他考虑因素:

介于两者之间的管道不会修复它:

$ echo "9
> 10
> 9
> 11" | cat - | awk '!seen[$0]++'
bash: !seen[$0]++': event not found

设置set +H turns history off,因此效果不错,因为它不会尝试扩展任何内容:

$ set +H
$ echo "9
> 10
> 9
> 11" | awk '!seen[$0]++'
9
10
11

我在how to address error “bash: !d': event not found” in Bash command substitution上通过rici的规范回答,发现了很多可能的原因,但没有一个符合这种行为。

1 个答案:

答案 0 :(得分:2)

这不是一个错误。

在bash-bugs邮件列表中询问后,我得到了以下答案:

  

历史扩展明确是面向行的。

     

它不知道shell状态,特别是shell引用状态,   跨越线条。

     

它确实知道模糊的贝壳式引用,这种引用在整个过程中很常见   大量的Unix实用程序 - 自历史和readline以来   库在shell之外使用 - 而且是双引号   引入了带引号的字符串,其中单引号不重要   并且不要抑制历史扩张。