我很难理解命名管道。我有以下脚本:
#!/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 &
现在我期待这个脚本做的是:
a_or_b
,因此打印func begin
loop begins
pipe
读取(因为我没有写任何东西到pipe
)因此打印1
作为$?
虽然我没有输出运行这个脚本,我的终端只是打印它的下一个提示。
如果我在调用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
(对应于输出中的两个\n
s)读取echo
和0
字符,然后在未读取任何字符时保持循环。如果我将a
或b
回到管道中,则该功能结束。
造成所有这些不同行为的原因是什么?
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是一个单独的进程写入它。啊哈!两个进程打开了管道,一个用于读取,一个用于写入。他们现在都可以继续了。鸟儿们唱歌,每个人都很开心。