FIFOに書き込むときにSIGPIPEをキャッチする

FIFOに書き込むときにSIGPIPEをキャッチする

問題を再現する手順は次のとおりです。

writer:

#!/bin/bash
trap 'echo NoReader!' PIPE
cat > fifo

2 つの端末を開きます。以下の>T1<タイトルとタイトルを使用して>T2<これを表現し、プロンプトを使用してそれを表現します$

>T1<
$ mkfifo fifo
$ bash writer
ABC
>T2<
$ cat fifo
ABC
^C
>T1<
DEF
$ echo $?
141

~からman fifo

SIGPIPE 信号は、もう一方の端で読み取るために開いていない FIFO に書き込もうとすると、プロセスに送信されます。

私が入力したとき、DEFFIFOにリーダーが残っていませんでした。そのため、入力後にSIGPIPEのトラップがトリガーされ、DEF適切なNoReader! メッセージが表示されると予想しました。代わりに、プロセスは自動的に終了します。エラーコードは141、これは実際にSIGPIPEによって終了されたことを示します。

一方、これを実行するとnewWriter

#!/bin/bash
trap 'echo NoReader!' PIPE
var=$(head -c 100000 /dev/urandom)
echo "$var" > fifo

head -c 1 fifo実際に第1ターミナルと第2ターミナルでトラップが発動されます!ただし、urandomから100000バイトではなく1000バイトのみを抽出すると、トラップはトリガされません。

私は何を見逃していますか?最初の例では、トラップはトリガーされていませんが、1000バイトではなく100000バイトwriterでトリガーされるのはなぜですか?newWriter

答え1

トラップハンドラが実行されない理由は、単に信号が受信されなかったためbashです。bash書き込みプロセスにのみ送信されますcat

シェル自体が書き込み操作を実行すると、トラップハンドラが実行されます。

#!/bin/bash

exec 3>fifo
trap 'echo NoReader!' PIPE
while IFS= read -r -d '' -n 1 input; do
    printf %s "$input" >&3 || break
done </dev/urandom

strace呼び出しの他の動作の理由を示しますhead。 FIFOバッファ4096バイト(私のシステムでは、何らかの方法でこの値をカーネルから取得できます)。したがって、-c 4096butを使用してもエラーは発生しないでください4097

関連情報