为什么 zsh 等待此命令完成,而 bash 在完成之前写入提示符?

为什么 zsh 等待此命令完成,而 bash 在完成之前写入提示符?

这是命令:

{ ( echo "to stdout"; echo "to stderr" >&2 ) > >(sleep 1; tee stdout.txt); } 2> >(sleep 2; tee stderr.txt >&2 )

这是我所看到的:

桀骜

% { ( echo "to stdout"; echo "to stderr" >&2 ) > >(sleep 1; tee stdout.txt); } 2> >(sleep 2; tee stderr.txt >&2 )
to stdout
to stderr
%

巴什

$ { ( echo "to stdout"; echo "to stderr" >&2 ) > >(sleep 1; tee stdout.txt); } 2> >(sleep 2; tee stderr.txt >&2 )
$ to stdout
to stderr

请注意,bash 在输出完成之前写入提示$,但 zsh 在提示用户之前会等待替换进程完成%

我想一个合理的答案可能是“因为 zsh 就是这样工作的”,但我想知道这是否在任何地方都有记录,以便我可以了解更多信息。作为众多 bash 用户中的 zsh 用户,我尝试了解其中的差异,以便知道当我说“嘿,运行这个命令”时会发生什么。

(相关问题:https://stackoverflow.com/a/53051506/1054322

答案1

较短的示例在两个 shell 中的行为方式相同。父 shell 不会等待。

(sleep 1; echo done) > >(cat >file) &

通过以下修改,zsh 将要等等,但bash不会:

{ (sleep 1; echo done) & } > >(cat >file)

zshexpn(1)手册中的“PROCESS SUBSTITUTION”下给出了类似的示例。在那里,它提到当将异步进程的输出重定向到进程替换(在两个 shell 中也是异步的)时,shell 将等待异步进程,{ ... }但如果没有{ ... }.

该手册将问题描述为

还有一个额外的问题>(process);当它附加到外部命令时,父 shell 不会等待进程完成,因此紧随其后的命令不能依赖结果的完成

通过将异步命令封装在一个compound中{ ... },“这里的额外进程是从父shell中生成的,父shell将等待它们的完成”。我对此的解释是,我们重定向到的进程>(...)将从 shell 中生成,而 without{ ... }则将从我们作为后台作业启动的作业中生成(因此 shell 不会等待它)。

$ZSH_SUBSHELL如果您在重定向到的进程替换中进行输出,则可以找到这方面的证据。对于阻塞代码,它将输出1,而对于非阻塞代码,它将输出2,表明输出重定向作为另一个子 shell 中的子 shell 运行(主 shell 不会等待)。

shellbash似乎以不同的方式处理这个问题,并在这两种情况下独立于父 shell 生成所有后台作业,即使$BASH_SUBSHELL在输出进程替换中的输出表现出与 中相同的行为zsh

相关内容