在后台进程中使用命名管道时的不同行为
Varying behavior when using named pipe with background process
我很难理解命名管道。我有以下脚本:
#!/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
- 从 stdin 读取一个 EOF,因此从
pipe
(因为我没有写任何东西到 pipe
),因此将 1
打印为 $?
- 两个 case 从句都不匹配,因此返回步骤 2
当 运行 这个脚本虽然我没有输出,我的终端只是打印它的下一个提示。
如果我在调用 a_or_b
:
之前将 echo 重定向到 pipe
...
mkfifo pipe
echo 'x' > pipe
a_or_b <pipe &
...脚本不会停止 运行,我可以继续在终端中输入字符(包括 a
和 'b'),但没有任何效果。所以我必须使用 ^C.
结束脚本
如果我将 echo 重定向到 pipe
after 调用 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
。函数开始,进入循环,从echo
中读取x
和\n
字符(对应输出中的两个0
),然后一直循环下去而无法读取任何字符。如果我 echo a
或 b
进入管道,函数结束。
是什么导致所有这些不同的行为?
a_or_b <pipe &
在启动命令之前处理重定向。 shell 块试图打开 pipe
进行阅读。来自 mkfifo(3) man page:
Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa.
在另一个进程打开 FIFO 进行写入之前,shell 无法继续。只有这样它才会完成重定向设置并实际调用 a_or_b
.
echo 'x' > pipe
a_or_b <pipe &
不幸的是,这有相同但相反的问题。在另一个进程打开 FIFO 进行读取之前,shell 无法继续通过 > pipe
重定向。它永远不会到达 echo
或从管道读取的第二行。
a_or_b <pipe &
echo 'x' > pipe
希望您现在可以明白为什么这个版本有效。后台 shell 尝试从管道和块中读取。前台shell,一个单独的进程,写入它。啊哈!两个进程打开了管道,一个用于读取,一个用于写入。他们现在都可以继续了。鸟语花香,皆大欢喜。
我很难理解命名管道。我有以下脚本:
#!/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
- 从 stdin 读取一个 EOF,因此从
pipe
(因为我没有写任何东西到pipe
),因此将1
打印为$?
- 两个 case 从句都不匹配,因此返回步骤 2
当 运行 这个脚本虽然我没有输出,我的终端只是打印它的下一个提示。
如果我在调用 a_or_b
:
pipe
...
mkfifo pipe
echo 'x' > pipe
a_or_b <pipe &
...脚本不会停止 运行,我可以继续在终端中输入字符(包括 a
和 'b'),但没有任何效果。所以我必须使用 ^C.
如果我将 echo 重定向到 pipe
after 调用 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
。函数开始,进入循环,从echo
中读取x
和\n
字符(对应输出中的两个0
),然后一直循环下去而无法读取任何字符。如果我 echo a
或 b
进入管道,函数结束。
是什么导致所有这些不同的行为?
a_or_b <pipe &
在启动命令之前处理重定向。 shell 块试图打开 pipe
进行阅读。来自 mkfifo(3) man page:
Opening a FIFO for reading normally blocks until some other process opens the same FIFO for writing, and vice versa.
在另一个进程打开 FIFO 进行写入之前,shell 无法继续。只有这样它才会完成重定向设置并实际调用 a_or_b
.
echo 'x' > pipe
a_or_b <pipe &
不幸的是,这有相同但相反的问题。在另一个进程打开 FIFO 进行读取之前,shell 无法继续通过 > pipe
重定向。它永远不会到达 echo
或从管道读取的第二行。
a_or_b <pipe &
echo 'x' > pipe
希望您现在可以明白为什么这个版本有效。后台 shell 尝试从管道和块中读取。前台shell,一个单独的进程,写入它。啊哈!两个进程打开了管道,一个用于读取,一个用于写入。他们现在都可以继续了。鸟语花香,皆大欢喜。