1
標準出力がパイプにリダイレクトされるPOSIXシェルスクリプトがあります。スクリプトの実行中にある時点でパイプが壊れる可能性があります。
だから私はこれを試しました:
(
trap "" PIPE # prevent shell from terminating due to SIGPIPE
while :; do
echo trying to write to stdout >&2
echo writing something to stdout || break
echo successfully written to stdout >&2
sleep 1
done
echo continuing here after loop >&2
) | sleep 3
以下を印刷します。
trying to write to stdout
successfully written to stdout
trying to write to stdout
successfully written to stdout
trying to write to stdout
successfully written to stdout
trying to write to stdout
sh: 5: echo: echo: I/O error
continuing here after loop
この例では、sleep
スクリプトを使用してプログラムの標準出力を置き換えます。 3秒後にsleep
終了し、パイプが切断されます。
私たちはstdoutだけをパイピングするので、sleep
stderrを使用してその間にいくつかのデバッグメッセージを処理できます。
規制によると、破損したパイプに書き込むとSIGPIPEが発生し、デフォルトの動作はプログラムを終了することです。POSIXsignal.h
。そのため、私たちはtrap
信号を受け入れて無視しなければなりません。
終了時にsleep
パイプが中断され、続いてecho writing something to stdout
SIGPIPEが発生して捕捉(無視)され、echo
失敗して|| break
ループを終了します。スクリプトは問題なく実行され続けます。
だから上記の例はうまくいきます。明らかな主な欠点は、パイプラインがまだ機能していることを確認するために「stdoutに書き込む」の多くを使用してパイプラインにスパムを送信することです。 「書き込み」パイプecho writing something to stdout
と交換すると、printf ""
パイプが損傷してから古いにもかかわらず、SIGPIPEが発生せずにループが続行されます。
どうですか?
ベストアンサー1
スクリプトの実行中にどの時点でパイプが壊れ、いつこのようなことが起こるのかを知りたいです。
パイプに書き込もうとするときにのみこれがわかります。
write()
Linuxのマニュアルページによると、リーダーなしでパイプの書き込み側へのすべての呼び出しは、ゼロバイトが書き込まれても信号/エラーを提供する必要があるようです。しかし、私が試しているシェルは、印刷するものがなければシステムコール全体をスキップするので役に立ちません。
ゼロ以外の量のデータを書き込む場合は、書き込み中にある時点でスクリプトがブロックされることがわかります。つまり、リーダがジョブの完了を無視し、パイプバッファがいっぱいになる場合です。
そしてまたコメントでこう言われました。
基本的にシェルスクリプトで選択/ポーリングを使用したいと思います。
...この場合、実際にはシェルから正しいプログラミング言語に切り替える必要があります。または、zselect
フロントエンドとして使用できるモジュールがあるZshに切り替えてくださいselect()
。https://zsh.sourceforge.io/Doc/Release/Zsh-Modules.html#The-zsh_002fzselect-Module
select()
パイプの読み取り端が閉じたときに見つけるのに役立たないと確信しています。