使用带有后台进程的命名管道时的不同行为

问题描述 投票:2回答:1

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

#!/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作为$?
  4. 两种情况都不匹配,因此请回到第2步

虽然我没有输出运行这个脚本,我的终端只是打印它的下一个提示。


如果我在调用pipe之前将回路重定向到a_or_b

...

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

...脚本不会停止运行,我可以继续在终端输入字符(包括a和'b')无效。所以我必须使用^ C结束脚本。


如果我在调用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(对应于输出中的两个\ns)读取echo0字符,然后在未读取任何字符时保持循环。如果我将ab回到管道中,则该功能结束。


造成所有这些不同行为的原因是什么?

bash background-process named-pipes
1个回答
3
投票
a_or_b <pipe &

在启动命令之前处理重定向。 shell阻止尝试打开pipe进行阅读。来自mkfifo(3) man page

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

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


echo 'x' > pipe
a_or_b <pipe &

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


a_or_b <pipe &
echo 'x' > pipe

希望你现在可以看到为什么这个版本有效。后台shell尝试从管道和块中读取。前台shell是一个单独的进程写入它。啊哈!两个进程打开了管道,一个用于读取,一个用于写入。他们现在都可以继续了。鸟儿们唱歌,每个人都很开心。

© www.soinside.com 2019 - 2024. All rights reserved.