将命名管道与后台进程一起使用时的各种行为

时间:2019-03-18 17:42:15

标签: bash background-process named-pipes

我很难理解命名管道。我有以下脚本:

#!/bin/bash

function a_or_b {
   echo 'func begins'

   while true; do
      echo 'loop begins'

      read -s -n 1; echo $?
      case $REPLY in
         'a') return 0 ;;
         'b') return 1 ;;
      esac
   done

   echo 'func ends'
}

mkfifo pipe
a_or_b <pipe &

现在我期望此脚本执行的操作是:

  1. 输入a_or_b,然后打印func begin
  2. 进入循环并因此打印loop begins
  3. stdin 中读取 EOF ,因此从pipe中读取(因为我还没有写任何东西到pipe),因此打印{{ 1}}作为1
  4. 两个案例都不匹配,因此请返回步骤2

运行此脚本时,尽管没有任何输出,并且终端仅显示其下一个提示。


如果我将 echo 重定向到$?,然后呼叫pipe

a_or_b

...该脚本不会停止运行,我可以继续在终端中输入字符(包括... mkfifo pipe echo 'x' > pipe a_or_b <pipe & 和'b'),但无效。所以我必须使用 ^ C 结束脚本。


如果我在调用a 之后将 echo 重定向到pipe

a_or_b

...我得到以下输出:

...

mkfifo pipe
a_or_b <pipe &
echo 'x' > pipe

这基本上是我期望的不从任何东西回波到func begins loop begins 0 loop begins 0 loop begins 1 loop begins 1 loop begins 1 的行为。函数开始,进入循环,从pipe读取x\n字符(对应于输出中的两个echo),然后一直循环而无法读取任何字符。而且,如果我在管道中 0a回显,则函数结束。


是什么原因导致所有这些不同的行为?

1 个答案:

答案 0 :(得分:3)

a_or_b <pipe &

在启动命令之前先处理重定向。外壳程序阻止尝试打开pipe进行读取。来自mkfifo(3) man page

  

打开FIFO以正常读取块,直到其他进程打开相同的FIFO进行写入为止,反之亦然。

只有在另一个进程打开FIFO进行写入之后,shell才能继续进行。只有这样,它才能完成重定向的设置并实际调用a_or_b


echo 'x' > pipe
a_or_b <pipe &

不幸的是,这具有相同但相反的问题。在另一个进程打开FIFO进行读取之前,shell无法继续通过> pipe重定向。它永远不会到达echo或从管道读取的第二行。


a_or_b <pipe &
echo 'x' > pipe

希望您现在可以看到此版本为何起作用。后台外壳程序尝试从管道和块中读取。前景外壳程序是一个独立的进程,会对其进行写入。啊哈!有两个过程打开了管道,一个过程用于读取,一个过程用于写入。他们现在都可以继续进行。鸟儿唱歌,每个人都很开心。