为什么命令可以{ echo err >&2; echo out >&1; } | :
打印“err”,而第二个命令却不能?
容器中的一些测试:
- 德班:11.5(bash/5.1.4)
- 洛基Linux:9.0(bash/5.1.8),
- 中央操作系统:1908 年 7 月 7 日(bash/4.2.46),
- CentOS:8.4.2105(bash/4.4.19)。
这也发生在主机 CentOS 8.0.1905、Debian 11.4 中。
~# { echo err >&2; echo out >&1; } | :
err
~# { echo out >&1; echo err >&2; } | :
~#
不使用:
似乎是正确的:
~# { echo out >&1; echo err >&2; } | sed 's/.*/-&-/'
err
-out-
~#
但在另一台主机CentOS 7.7.1908(bash/4.2.46)中打印:
~# { echo out >&1; echo err >&2; } | :
err
~#
答案1
和...之间的不同
{ echo err >&2; echo out >&1; } | :
... 和
{ echo out >&1; echo err >&2; } | :
echo
...是两次调用的顺序。顺序仅就如何进行而言很重要迅速地第一个echo
可以执行。
管道的两侧{ ...; }
和:
是同时启动的,并且:
不从其标准输入流读取。这意味着管道一旦:
终止就会被拆除,几乎是立即拆除。
如果管道被拆除,则没有管道缓冲区可供echo out >&1
写入。当echo
尝试写入不存在的管道时,管道的左侧会因接收 PIPE 信号而死亡。
如果它在echo err >&2
执行之前就死掉了,那么就没有输出。
所以:
您将始终获得
err
输出,{ echo err >&2; echo out >&1; } | :
因为echo err >&2
不会关心管道的状态。有时您会得到
err
以下输出{ echo out >&1; echo err >&2; } | :
根据:
之前是否已经终止了echo out >&1
还有机会运行。如果:
先终止,则由于左侧过早被杀死,将不会有输出。
我猜大多数人不会在大多数系统上经历第二个管道的非确定性行为。尽管如此,您还是发现了显示这一点的操作系统和 shell 版本的组合。我还在 FreeBSD 上复制了非确定性行为zsh
,即使是在单个 shell 会话中(尽管 shell 似乎倾向于一种行为而不是另一种行为,所以我需要 10 次以上的尝试才能最终看到切换)。
答案2
(首先,如果您正在尝试一些东西并且不确定它们如何工作以及它们做什么,我强烈建议您在登录时停止这样做root
)
{ echo err >&2; echo out >&1; } | :
这将回显 string err\n
,其中包含该字符串的标准输出重定向到标准错误(显示在终端上),然后将字符串回显out\n
到标准输出,毫无意义地重定向到标准输出;然后,该标准输出作为标准输入通过管道传输到:
,它不输出任何内容。
进一步测试:
$ { echo err >&2; echo out >&1; } 1> outputfile 2> errorfile
$ for file in *; do echo $file; cat $file; done
errorfile
err
outputfile
out
$ rm errorfile outputfile
$ { echo err >&2; echo out >&1; } 1> outputfile 2> errorfile
$ for file in *; do echo $file; cat $file; done
errorfile
err
outputfile
out
综上所述,我不确定为什么在某些情况下您似乎会丢失标准错误的输出。我无法复制这个:
$ { echo err >&2; echo out >&1; } | :
err
$ { echo out >&1; echo err >&2; } | :
err