`yes` を別のコマンドにパイプすると何が起こりますか?

`yes` を別のコマンドにパイプすると何が起こりますか?

コマンドが強制終了されるまで「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

関連情報