fifo から read するスクリプトの挙動が、 OS 間で異なっている理由がわからない
次のような、名前付きパイプ(fifo) を利用するスクリプトを記述しました。
#!/bin/sh
set -ex
rm -rf fifo
mkfifo fifo
cat <<EOF > fifo &
hoge
fuga
moge
EOF
while read -r line < fifo
do
echo $line
done
echo "EOF!"
これを、 Mac OS X で実行した時には、途中で処理が止まってしまいます。 (Ctrl+C で中止している)
$ ./test-fifo.sh
+ rm -rf fifo
+ mkfifo fifo
+ read -r line
+ cat
+ echo hoge
hoge
+ read -r line
^C
一方、 ubuntu(14.04, dash0.5.7) 上で実行した場合には、意図通りにスクリプトは実行できています。
$ ./test-fifo.sh
+ rm -rf fifo
+ mkfifo fifo
+ read -r line
+ cat
+ echo hoge
hoge
+ read -r line
+ echo fuga
fuga
+ read -r line
+ echo moge
moge
+ read -r line
+ echo EOF!
EOF!
質問:
- どうして、このような OS 間の挙動の差異が発生するのでしょうか。
仮説(考えたこと)
このスクリプトの挙動はそもそも undefined である。
- ただ、だとするとその旨の記述はどこかに仕様として記述があるのでは、と考えていて、それが見つけられないと考えている状態です。
OS 間で fifo の挙動が、仕様として差異がある。
- この場合も同様に、その仕様がどこかにまとまっていると考えていますが、それをどうやったら探せるのかわからないと思っている状態です。
追記@ 2016/04/03
手元の ubuntu 環境(14.04) だと、 bash でも dash でも、同じようによろしく動いてしまっています。。
bash
$ bash test-fifo.sh
+ rm -rf fifo
+ mkfifo fifo
+ read -r line
+ cat
+ echo hoge
hoge
+ read -r line
+ echo fuga
fuga
+ read -r line
+ echo moge
moge
+ read -r line
+ echo 'EOF!'
EOF!
dash
$ dash test-fifo.sh
+ rm -rf fifo
+ mkfifo fifo
+ read -r line
+ cat
+ echo hoge
hoge
+ read -r line
+ echo fuga
fuga
+ read -r line
+ echo moge
moge
+ read -r line
+ echo EOF!
EOF!
自分の手元の、よろしく動いてしまう ubuntu で、 dash/bash の strace
を見る限りは、次のような動作をしていました。
hoge\nfuga\nmoge
を cat するプロセスが、この文字列を fifo に write する。 write システムコールが発行されて、このプロセスの実行がしばらく止まる。- シェルが1文字ずつ read する。
hoge\n
になったら fifo を close する。 - シェルが echo 処理を行う
- シェルが再び fifo をオープンして、 手順の 2 に戻る
- 2-4 を繰り返して、
hoge\nfuga\nmoge\n
がなくなると、 cat プロセスに実行が戻る。 cat プロセスが正常終了する。 - read で何も読み込めなかったので、 while のループを抜ける。その後正常終了する。
プロセスの実行タイミングと、 fifo の fd の open/close のタイミングの問題な気がしてきています。