単にread
を実行すると、1行を読み取り、 Enter が押されます。
$ read
typing something here
$
ただし、パイプを介して入力を渡すと、 from cat
、read
は動作が異なり、2番目の改行に遭遇するまで実行を続けます。
$ cat | read
typing first line
typing second line
$
なぜこのようになっているのか誰にも説明できますか?
改行とは何の関係もありません。
strace
を使用してコマンドを実行すると、cat
が終了する前に、最後にSIGPIPE
を受け取ることがわかります。
$ strace cat | read
...
someOutput
...
+++ killed by SIGPIPE +++
cat
コマンドが実行されます。read
にパイプされます。cat
はまだ実行中で、EOFを待機しています。今回は、read
にパイプすることはできません。これは、次のように実行しない限り、入力を待機するread
がなくなったためです(最初のパイプの後に閉じられました)。
cat | while read line; do echo $line; done;
cat
はSIGPIPE
を受け取り、閉じられます。プロセスは、リーダーが残っていないタイプのSOCK_STREAMのパイプ(名前付きまたは名前なし)またはソケットに書き込もうとすると、SIGPIPEを受け取ります。 [1]
2番目のパイプが発生すると、SIGPIPE
を受信しますafterが発生します。
たとえば、yes
コマンドは、yes
のようなコマンドが高速で繰り返しパイプするため、考えてみてください。
yes | read
2番目のパイプの直後に閉じられます。2つのwrite()
呼び出しに注意してください。
close(3) = 0
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = 8192
write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8192) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=3542, si_uid=1000} ---
+++ killed by SIGPIPE +++
yes
コマンドは速すぎるため、2つ以上のwrite()
コールが表示される場合がありますが、複数回実行すると、少なくとも2つのコールが表示され、1つは表示されません。