名前付きパイプを使用したbash IPC

名前付きパイプを使用したbash IPC

次のスクリプトを検討してください

#!/usr/bin/bash

chan=/tmp/pipe.$$
mkfifo $chan
{
    for x in a b c d e
    do
        echo $x > $chan
    done
} &
for y in 1 2 3 4 5
do
    x=$(cat $chan)
    echo "var $x = $y ;"
done
rm $chan

期待どおりに動作しないようです。例えば

❯ ./testpipe.sh
var a
b
c = 1 ;
^C

fifoにリーダーがいないとエコー待機してはいけませんか?端末でこれを行うと、期待どおりに停止します。

❯ mkfifo /tmp/pipe
❯ echo 1 > /tmp/pipe
^C

スクリプトでなぜ異なる動作をしますか?


修正する

毎回開かずにfdsを使うように切り替えました。

#!/usr/bin/bash
chan=/tmp/pipe.$$
mkfifo $chan    
{
    exec 5>"$chan"
    for x in a "ba ba ba baanannna" c d e
    do
        echo $x >&5
    done
} &

exec 6<"$chan"
for y in 1 2 3 4 5
do
    read -u 6 x
    echo "var $x = $y ;"
done
rm $chan

私は問題を修正したのか、それともゲームをより珍しいものにしたのかはわかりません。

❯ ./testpipe.sh
var a = 1 ;
var ba ba ba baanannna = 2 ;
var c = 3 ;
var d = 4 ;
var e = 5 ;

アップデート2

FIFOはまったく必要ありません。 procの置換だけでバックグラウンドで何かを実行し、必要に応じて読み取ることができます。生産者と消費者に省電力モードを追加する前後にテストされました。うまくいくようです。ゲームがないかもしれません。

#!/usr/bin/bash

produce()
{
    for x in a "ba ba ba   baanannna" "more    space" d e
    do
        echo "$x"
    done
}

exec {fd}< <(produce)
for y in 1 2 3 4 5
do
    read -u $fd x
    echo "var $x = $y ;"
done

答え1

Running in background shell -- running in foreground shell

echo a waits
                        cat opens read side
                        cat is maybe faulting in some pages or maybe not just picked 
                        but for whatever reason doesn't immediately call read
echo a completes
echo b doesn't wait (read side already open) and completes
echo c ditto
                        cat calls read, gets a NL b NL c NL and writes them 
                        (but the shell's $(...) that reads them drops the final NL)
echo d probably doesn't wait, but might if cat has close'd already (race condition)

成功すれば、$(cat <$chan)すべてのaeを得ることができます。サブシェル読み込み前に cat を実行する前に読み込み側を開いて待ち時間を増やします。 OTOHプロデューサーを使用しcommand echoたり/bin/echo速度を遅くしたりすると、おそらく1つしか入手できません。

関連情報