如果我只是运行,read
它会读取一行并在Enter按下时立即退出。
$ read
typing something here
$
但是,当我通过管道传递输入(例如 from )时cat
,read
行为会有所不同并一直运行直到遇到第二个换行符:
$ cat | read
typing first line
typing second line
$
有人能解释一下为什么会这样吗?
PS:这个问题的灵感来自如何同时提供标准输入并转储到文件?
答案1
它与换行符没有任何关系。
如果您使用 运行命令strace
,您会发现在关闭之前,遗嘱在末尾cat
收到了一个:SIGPIPE
$ strace cat | read
...
someOutput
...
+++ killed by SIGPIPE +++
- 第一个
cat
命令开始运行。 - 然后您第一次输入一些内容并点击Enter。
- 您输入的内容将通过管道传输到
read
。 cat
仍在运行并等待 EOF。- 您输入其他内容然后Enter再次点击。
这次,它无法通过管道传输到
read
,因为不再read
等待输入(第一个管道后它已关闭),除非您像这样运行它:cat | while read line; do echo $line; done;
cat
将会收到SIGPIPE
并关闭。
当进程尝试写入管道(无论是否命名)或没有读取器的 SOCK_STREAM 类型的套接字时,它会收到 SIGPIPE。[1]
接收SIGPIPE
发生后当第二根管道发生时。
例如考虑yes
命令,因为像管道这样的命令yes
快速且重复地传输某些内容:
yes | read
它在第二个管道之后立即关闭,注意两个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
命令太快,您可能会看到超过两个write()
调用,但是如果您运行它几次,您将看到至少两个调用,而不会看到一个调用。