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

qye*_*cst 5 shell bash pipe command

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

容器中的一些测试:

  • Debian:11.5(bash/5.1.4)
  • 洛基 Linux:9.0(bash/5.1.8),
  • CentOS: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; } | :
~#
Run Code Online (Sandbox Code Playgroud)

不使用:似乎是正确的:

~# { echo out >&1; echo err >&2; } | sed 's/.*/-&-/'
err
-out-
~#
Run Code Online (Sandbox Code Playgroud)

但在另一台主机CentOS 7.7.1908(bash/4.2.46)中打印:

~# { echo out >&1; echo err >&2; } | :
err
~#
Run Code Online (Sandbox Code Playgroud)

Kus*_*nda 9

和...之间的不同

{ echo err >&2; echo out >&1; } | :
Run Code Online (Sandbox Code Playgroud)

... 和

{ echo out >&1; echo err >&2; } | :
Run Code Online (Sandbox Code Playgroud)

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 次以上的尝试才能最终看到切换)。