7

我在 GNU bash,版本 4.3.11。

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

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

但是,如果我从标准输入获取输入,在多行中使用双引号并通过管道连接到 awk,则会失败:

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

也就是 bash 试图扩展 command 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会关闭历史记录,因此它运行良好,因为它不会尝试扩展任何内容:

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

我浏览了 rici 关于如何在 Bash 命令替换中解决错误“bash: !d': event not found”的规范答案,发现了许多可能的原因,但没有一个与这种行为匹配。

4

1 回答 1

2

这不是一个错误。

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

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

它不知道跨行的 shell 状态,尤其是 shell 引用状态。

它确实知道在大量 Unix 实用程序中常见的类似 shell 的模糊引用——因为历史和 readline 库在 shell 之外使用——并且双引号引入了一个带引号的字符串,其中单引号不重要,并且不要抑制历史扩展。

于 2016-06-20T08:13:06.593 回答