web-dev-qa-db-ja.com

エコークローズを回避する方法FIFO名前付きパイプ?-Unix FIFOの面白い動作

いくつかのデータをパイプに出力し、他のプロセスに1行ずつデータを処理させます。おもちゃの例を次に示します。

mkfifo pipe
cat pipe&
cat >pipe

これで、好きなものを入力でき、Enterを押すとすぐに同じ行が表示されます。ただし、2番目のパイプをechoで置き換える場合:

mkfifo pipe
cat pipe&
echo "some data" >pipe

パイプはechoおよびcat pipe&が終了した後に閉じられるため、パイプを介してこれ以上データを渡すことはできません。パイプとデータを受信するプロセスを閉じないようにする方法はありますか?それにより、bashスクリプトからパイプを介して多くのデータ行を渡し、それらが到着したときに処理することができますか?

50
user1084871

FIFO=が読み取り用に開かれている場合、呼び出しプロセスをブロックします(通常)。プロセスがFIFO書き込み用に開かれている場合、リーダーはブロック解除されます。ライターがFIFOを閉じると、読み込みプロセスはEOF(読み込む0バイト)を取得し、FIFOしたがって、ループを使用する必要があります。

mkfifo pipe
(while cat pipe; do : Nothing; done &)
echo "some data" > pipe
echo "more data" > pipe

別の方法は、FIFO open。

mkfifo pipe
sleep 10000 > pipe &
cat pipe &
echo "some data" > pipe
echo "more data" > pipe
47

Fifoに出力するすべてのステートメントを同じサブシェルに配置します。

# Create pipe and start reader.
mkfifo pipe
cat pipe &
# Write to pipe.
(
  echo one
  echo two
) >pipe

さらに複雑な場合は、書き込み用のパイプを開くことができます。

# Create pipe and start reader.
mkfifo pipe
cat pipe &
# Open pipe for writing.
exec 3>pipe
echo one >&3
echo two >&3
# Close pipe.
exec 3>&-
52
Mark Edgar

これは、パイプの読み取り側を読み取り/書き込みモードで開くことで非常に簡単に解決できます。リーダーはEOFを取得するのは、最後のライターが閉じたときだけです。読み取り/書き込みで開くと、常に少なくとも1人のライターが存在することが保証されます。

2番目の例を次のように変更します。

mkfifo pipe
cat <>pipe &
echo "some data" >pipe
21
Patrick

正直なところ、これを機能させるための最良の方法は、基本的に2つのソケットを接続するsocatを使用することでした。

mkfifo foo
socat $PWD/foo /dev/tty

新しい用語では、次のことができます。

echo "I am in your term!" > foo
# also (surprisingly) this works
clear > foo

欠点はsocatが必要なことです。これは誰もが手に入れる基本的なユーティリティではありません。プラス面は、機能しないものが見つからないことです...色を印刷したり、teeをfifoに出力したり、画面をクリアしたりできます。ターミナル。

2
Jordan

パイプのクローズをサポートするために、ジョナサンレフラーの回答から2番目のバージョンを強化しました。

dir=`mktemp -d /tmp/temp.XXX`
keep_pipe_open=$dir/keep_pipe_open
pipe=$dir/pipe

mkfifo $pipe
touch $keep_pipe_open

# Read from pipe:
cat < $pipe &

# Keep the pipe open:
while [ -f $keep_pipe_open ]; do sleep 1; done > $pipe &

# Write to pipe:
for i in {1..10}; do
  echo $i > $pipe
done

# close the pipe:
rm $keep_pipe_open
wait

rm -rf $dir
2
silyevsk

ここでの他のソリューションの代替として、コマンドへの入力としてループでcatを呼び出すことができます。

mkfifo pipe
(while true ; do cat pipe ; done) | bash

これで、コマンドを1つずつフィードでき、閉じません。

echo "'echo hi'" > pipe
echo "'echo bye'" > pipe

もちろん、必要なときにプロセスを強制終了する必要があります。これは、プロセスを作成するときに非終了動作を指定できるため、最も便利なソリューションだと思います。

1
Adam Dingle