bash 如何对待 "> >()"

bash 如何对待 "> >()"

在尝试输出重定向和进程替换时,我偶然发现了以下命令及其结果输出:

    me@elem:~$ echo foo >>(cat);回声栏
    酒吧
    我@elem:~$ foo

(是的,末尾的空换行符是故意的。)

所以 bash echo 的 bar,打印我常用的提示符,echo 的 foo,echo 的换行符,并将光标留在那里。如果我再次按回车键,它将在新行上打印我的提示符并将光标保留在其后面(正如有人在空命令行上按回车键时所预期的那样)。

我期望它将 foo 写入文件描述符,cat 读取它并回显 foo,第二个回显 echo 的 bar,然后返回命令提示符。但事实显然并非如此。

有人可以解释一下发生了什么事吗?

答案1

您可能会在提示foo之前bar、之后bar甚至之后看到显示内容,具体取决于时间。添加一点延迟以获得一致的计时:

$ echo foo > >(sleep 1; cat); echo bar; sleep 2 
bar
foo
$

bar立即出现,然后foo一秒钟后出现,然后再过一秒后出现下一个提示。

发生的情况是 bash 在后台执行进程替换。

  1. 主 bash 进程启动一个子 shell 来执行sleep 1; cat,并为其设置一个管道。
  2. 主 bash 进程执行echo foo.由于这不会填满管道的缓冲区,因此该echo命令将终止而不会阻塞。
  3. 主 bash 进程执行echo bar.
  4. 主 bash 进程启动命令sleep 2
  5. 同时,子 shell 正在启动命令sleep 1
  6. 大约1秒后,sleep 1返回到子进程中。子进程继续执行cat
  7. cat将其输入复制到其输出(显示在屏幕上)并返回。
  8. 子 shell 已完成其工作,退出。
  9. 又过一秒,sleep 2返回。主 shell 进程完成执行,您将看到下一个提示。

答案2

您不需要替换进程即可获得该效果。尝试这个:

( echo foo | cat & )

您将得到大致相同的结果(没有bar;我将把它作为练习)并且出于相同的原因。在这两种情况下,cat都是作为后台任务启动的。在我这里,这是明确的。在进程替换的情况下,它也是明确的——它是一个附加到名称文件描述符的单独进程——但它可能不那么明显。

bash在打印下一个提示之前,子进程不一定终止。由于它的输出是缓冲的,因此在终止之前不会输出任何内容。此时,bash 刚刚$在 stderr 上打印,现在后台进程在打印foo和换行后退出。

相关内容