入力ストリームをパイプしようとしていますが、ダウンストリームパイプラインプログラムが失敗する可能性がある状況を捉えたいと思います。この場合は再起動する必要があります。だから私はそれをループに入れました。
step1 |while true ; do step2 ; done
しかし、アップストリームパイプを閉じると、ループが終了することを望みます。ステップ2の終了状態ではこれは不明です。それ以外の場合は、次のように言った可能性があります。
step1 |until [ $? -ne 0 ] ; do step2 ; done
stdinが閉じていることを確認しますが、実際にstdinの文字を使用しないテストが必要です。
Cではどうするのか気になります。バッファがゼロのread(2)を使用してこれをテストできますか?私はそうは思わない。オプション(2)はどうですか?いいえ。それともそうでしょうか? fcntl(2) はどうですか?何も見つかりません。
バイトを消費して何とか再出力する以外に、本当に他の方法はありませんか?ファイル記述子を閉じずにテストしますか?
答え1
少なくともLinuxでは、poll()
イベントマスクでwithを使用して、パイプのもう一方の端が閉じられているかどうかを知ることができます。POLLHUP
ただし、この時点で読み取るデータがパイプに残っている可能性があるため、そのデータも確認することをお勧めします。 Linuxでは、ioctlを介してこれを行うことができますFIONREAD
。
したがって、次のいずれかを定義できます。
stdin_alive() {
perl -MIO::Poll -e '
require "sys/ioctl.ph";
-p STDIN or die "stdin is not a pipe\n";
$p = IO::Poll->new;
$p->mask(STDIN, POLLHUP);
if ($p->poll(0)) {
ioctl(STDIN, &FIONREAD, $n) or die "FIONREAD: $!\n";
$n = unpack "L", $n;
exit 1 unless $n;
}'
}
次のように使用してください。
step1 | while stdin_alive; do step2; done
ifne
別の方法は、次のコマンドを使用することですmoreutils
。
step1 |
while
ifne sh -c 'step2 && exit 42'
[ "$?" -eq 42 ]
do
continue
done
ifne
標準入力をお読みください。少なくとも1バイトを読み取ると、コマンドifne
が開始され、対応する標準入力が新しいパイプに接続され、その新しいパイプを介して標準入力から読み取られた内容がコマンドに挿入されるため、追加のシャベルが発生し、効率が低下します。転送用の追加のパイプがありますが、これは入力タイプ(パイプだけでなく)に関係なく機能することを意味します。
以前の解決策とのもう1つの違いは、ifne
開始前にstdinへの入力を待ちますstep2
が、poll()
+FIONREAD
メソッドはパイプがアクティブであるかどうか、チェック時点の正確な時点にデータがあることを確認します。ただし、POLLIN
これはポーリングされるイベントのリストに追加することで変更できます。