
コマンドが強制終了されるまで「y」を継続的にエコーする場合yes
、コマンドは決して完了しません。コマンドが決して完了しない場合は、その出力を次のコマンドにパイプする方法は?
答え1
プログラムyes
は、リーダーと同時にパイプに書き込みます。パイプが空の場合、リーダーはカーネル内でブロックし、read()
さらなる入力を待ちます。パイプがいっぱいの場合、書き込みはカーネル内でブロックし、write()
リーダーがパイプ内のスペースを解放するのを待ちます。
カーネルは、SIGPIPE
プロセスがリーダーを持たないパイプに書き込もうとする場合、そのプロセスにシグナルを送信します。読み取りプロセスがパイプの読み取り側を閉じると (明示的に、または終了の結果として)、書き込みプロセスが次にパイプに書き込もうとするときに、シグナルを受信しますSIGPIPE
。
yes
この点を説明するために、の連続ストリームを出力するプログラムの簡略版を考えてみましょうy
。このプログラムは、シグナルyes
を受信するとメッセージを生成するという点でと異なりますSIGPIPE
。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
static void handler(int sig) {
#define msg "received SIGPIPE signal, terminating\n"
write(2, msg, sizeof msg);
exit(1);
#undef msg
}
int main(void) {
// Instruct the kernel to call the handler() function when
// this process receives the SIGPIPE signal. The default behavior
// when this signal is received is for the process to terminate.
signal(SIGPIPE, handler);
for (;;) {
if (write(1, "y\n", 2) < 0) {
fprintf(stderr, "%s\n", strerror(errno));
return 2;
}
}
return 0;
}
プログラムをコンパイルして実行すると、次のように動作することがわかりますyes
。
$ gcc ex.c -o myes
$ ./myes
y
y
y
...
出力を別のプロセスにパイプすると、そのプロセスが終了すると (パイプの読み取り側が閉じられると)、プログラムはシグナルmyes
を受信しますSIGPIPE
(関連するメッセージによって示されます)。
$ ./myes | head -n5
y
y
y
y
y
received SIGPIPE signal, terminating