这是命令:
{ ( echo "to stdout"; echo "to stderr" >&2 ) > >(sleep 1; tee stdout.txt); } 2> >(sleep 2; tee stderr.txt >&2 )
这就是我所看到的:
zsh
% { ( 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 )
较短的示例在两个 shell 中的行为方式相同。父外壳不等待。
通过以下修改,
zsh
将等待,但bash
不会:zshexpn(1)
手册中的“过程替换”下给出了类似的示例。{ ... }
在那里,它提到当将异步进程的输出重定向到进程替换(在两个 shell 中也是异步的)时,shell 将等待异步进程,但如果没有{ ... }
.手册将问题描述为
通过将异步命令包含在一个复合
{ ... }
中,“这里的额外进程是从等待它们完成的父 shell 产生的。” 我对此的解释是,我们重定向到的进程 with>(...)
将从 shell 中生成,而没有{ ... }
时,它将从我们作为后台作业启动的作业中生成(因此 shell 不会等待它)。如果您
$ZSH_SUBSHELL
在重定向到的进程替换中输出,则可以找到证据。使用阻塞代码,它将输出1
,而使用非阻塞代码,它将输出2
,表明输出重定向是作为另一个子shell中的子shell运行的(主shell不会等待)。shell 似乎以不同的
bash
方式处理这个问题,并且在这两种情况下都独立于父 shell 生成所有后台作业,即使$BASH_SUBSHELL
在输出进程替换中的输出表现出与zsh
.