在 zsh 中,cat

在 zsh 中,cat

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

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

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

谁能帮我理解 zsh 在幕后做了什么?

答案1

  1. a | bSTDOUT只需使用a即可连接STDINbdup/dup2。两个命令并行执行。

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

  3. a <(b)将参数替换为a命名管道。ab并行运行。现在事情变得有点复杂:

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

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

    • 这意味着您基本上遇到了死锁,a尝试读取bb无法读取STDIN且无法写入a

有关后台进程和终端的更多信息来自男人狂欢:

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

相关内容