`{ echo err >&2; 和有什么区别?回显>&1; } | :` 和 `{ 回显 >&1;回显错误>&2; } | :` 在 Bash 中?

`{ echo err >&2; 和有什么区别?回显>&1; } | :` 和 `{ 回显 >&1;回显错误>&2; } | :` 在 Bash 中?

为什么命令可以{ echo err >&2; echo out >&1; } | :打印“err”,而第二个命令却不能?

容器中的一些测试:

这也发生在主机 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

相关内容