在 zsh 中, cat <(cat) 与 cat | 之间的区别 猫 vs 猫 =(猫)?

Ala*_*ell 19 zsh process-substitution subshell

我期望cat <(cat)cat | cat做同样的事情:将行从标准输入复制到标准输出。我的理解是,两者都将cat在 subshel​​l 中执行 a ,将 subshel​​lcat的 stdout重定向到临时命名管道,然后cat在当前 shell 中执行另一个并将其 stdin 重定向到管道。

相反,cat <(cat)让我在终端上输入,但没有任何输入行被复制并且^D无法发出信号EOFcat | cat虽然按预期工作。

作为进一步的实验,我检查了是否cat =(cat)有与 类似的困难cat <(cat),但它按我的预期工作:直到 a 的所有标准输入^D都被一次性复制到标准输出。

任何人都可以帮助我了解 zsh 在幕后做了什么?

Ulr*_*gel 24

  1. a | b所连接STDOUT距离aSTDIN距离b只需使用dup/dup2。这两个命令是并行执行的。

  2. a =(b)将参数 to 替换为a临时文件名。b将在之前执行,a因为需要创建临时文件才能将其传递给a

  3. a <(b)a命名管道替换参数 to 。ab并行运行。这是现在变得有点复杂的地方:

    b在后台,无法从终端读取。您可以通过使用strace -p $PID附加到您的第二个 cat 进程以查看该进程来自行测试。

    a同时尝试从命名管道中读取,但无法读取任何内容,因为b无法读取。

    • 这意味着你基本上有一个死锁,a试图读取bb不能读取STDIN和不能写入a

man bash有关后台进程和终端的更多信息:

为了便于作业控制的用户界面的实现,操作系统维护了当前终端进程组 ID的概念。此进程组的成员(进程组 ID 等于当前终端进程组 ID 的进程)接收键盘生成的信号,例如 SIGINT。据说这些进程在前台背景进程是那些进程组 ID 与终端不同的进程;此类进程不受键盘生成信号的影响。只允许前台进程读取,或者,如果用户使用 stty tostop 指定,则写入终端。后台进程试图从终端读取(在 stty tostop 生效时写入)终端会被内核终端驱动程序发送一个SIGTTIN (SIGTTOU)信号,除非被捕获,否则会挂起进程。

  • 请注意,当不交互时,zsh 将 _background_ 命令的标准输入(包括 `&lt;(cmd)` 中的那些)重定向到 `/dev/null`,因此行为不同(`zsh -c 'cat &lt;(cat)'` 返回立即并且不输出任何内容)。 (3认同)