私はOSXを使用しており、bashを使用しており、パイプを理解しようとしています。私はプログラムがbashシェルと双方向で通信できるようにしたいと思います。常に同じシェルになるように設定してディレクトリに移動すると、bashはこれを覚えておくことができます(常に新しいbashシェルを使用する代わりに)。
私が今まで試したことはこれです。新しい端末(A)で実行
mkdir /tmp/IOdir
cd /tmp/IOdir
mkfifo pToB
mkfifo bToP
tail -f -1 pToB | bash >> bToP
その後、この接続をテストするために新しい端末(B)から起動できます。
cd /tmp/IOdir
echo echo hello > pToB
第3ターミナル(C)から出発
cd /tmp/IOdir
(read myline && echo $myline) < bToP
これが私が望む行動です。同じbashシェルはアクティブのままで、出力はもう一方の端を介して提供されます。後で参照できるように、この状況をXと呼んでください。
状態Xで続行
しかし今、このX状態からはもう同じことはできません。つまり、端末(B)で行うと
echo echo hello > pToB
その後、端末Cで
(read myline && echo $myline) < bToP
その後、ターミナルCでは何も入っていません。そしてまたこれを行うと、ターミナルBで
echo echo hello > pToB
Bash シェルが閉じます。
状態Xでできることは、まず端末Cで行うことです。
(read myline && echo $myline) < bToP
その後、ターミナルBから出発します。
echo echo hello > pToB
この場合、端末Cはhello信号をエクスポートし、状態Xに戻っているように見えます。だから私たちは基本的にこれを永遠に繰り返すことができます。今、これは双方向通信には十分に見えますが、私のプログラムは次のような新しい行を要求した場合です。
(read myline && echo $myline)
そして、新しい行がなければ「停止」されます(bashと同様に、実際にプログラムがbash呼び出しを使用するという意味です)。したがって、後で入力をpToBに送信することはできず、私ができることはありません。
質問
Cプログラミングをあまり使用せずにこれを設定する方法はありますか? 2つの名前付きパイプを使用せずにこれをよりエレガントに実行する方法はありますか?場合によってはパイプが閉じていますが、他の場合には閉じない原因は何ですか?
編集する
~からWikipediaのこのページ、私たちは
全二重(双方向)通信には通常、2つの匿名パイプが必要です。
一方では、少なくともパイプの数が正しいようです。一方、匿名パイプではなく名前付きパイプを使用します。だからおそらく難しいかもしれないし、不可能かもしれません。
また、mkfifoGNU/Linuxのソースコードそれはおそらくmknodに従って定義されているでしょう。GNU/Linuxのソースコード、これはUnixコマンドでもあります。しかし、私はそれから学ぶことがあまりないと確信しています。
ここパイプラインのLinuxソースコードを含むC言語パイプラインの紹介です。実際にこのようなことが起こったら、パイプが閉じた理由がわかります。
ここfifoが閉じないようにすることに関する質問です。私は答えでしたように、バックグラウンド睡眠プロセスにパイプを接続しようとしましたが、それは役に立ちませんでした。
答え1
理由はをご利用くださいstrace
。
tail -f | strace bash >> foo
二人目はecho echo hello > pToB
私にこう言いました。
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "e", 1) = 1
read(0, "c", 1) = 1
read(0, "h", 1) = 1
read(0, "o", 1) = 1
read(0, " ", 1) = 1
read(0, "h", 1) = 1
read(0, "e", 1) = 1
read(0, "l", 1) = 1
read(0, "l", 1) = 1
read(0, "o", 1) = 1
read(0, "\n", 1) = 1
write(1, "hello\n", 6) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=3299, si_uid=1000} ---
+++ killed by SIGPIPE +++
したがって、2番目にhello \ nを作成しようとすると、壊れたパイプエラーが発生するため、helloを読み取ることができず(作成されたことがない)、bashが終了します。
パイプを開いたままにするには、何かを使用する必要があると思います。
これはどうですか?
(while read myline; do echo $myline; done) < pToP
man 7 pipe
関連する追加の背景情報を表示するには、パイプ周辺のさまざまなエラー条件について説明します。
答え2
Frostschutzの回答の付録として、次の表を検討してください。
初めてbToPにhelloを送信しようとすると、fifoリーダーがあるまでブロックされます。 2番目に、リーダーはBashを終了するSIGPIPE信号を送り返します。これを無視しても、後で EPIPE エラーが発生する可能性があります。
私がやろうとしていることは不可能だと思います。私のアプリケーションは「同時に読み書きできません」。パイプの両側を開いたままにする中間プログラムを作成する必要があるようです。