如果输入通过管道,“读取”命令等待额外的换行符

如果输入通过管道,“读取”命令等待额外的换行符

如果我只是运行,read它会读取一行并在Enter按下时立即退出。

$ read
typing something here
$

但是,当我通过管道传递输入(例如 from )时catread行为会有所不同并一直运行直到遇到第二个换行符:

$ cat | read
typing first line
typing second line
$

有人能解释一下为什么会这样吗?

PS:这个问题的灵感来自如何同时提供标准输入并转储到文件?

答案1

它与换行符没有任何关系。

如果您使用 运行命令strace,您会发现在关闭之前,遗嘱在末尾cat收到了一个:SIGPIPE

$ strace cat | read

...
someOutput
...
+++ killed by SIGPIPE +++
  1. 第一个cat命令开始运行。
  2. 然后您第一次输入一些内容并点击Enter
  3. 您输入的内容将通过管道传输到read
  4. cat仍在运行并等待 EOF。
  5. 您输入其他内容然后Enter再次点击。
  6. 这次,它无法通过管道传输到read,因为不再read等待输入(第一个管道后它已关闭),除非您像这样运行它:

    cat | while read line; do echo $line; done;
    
  7. 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()调用,但是如果您运行它几次,您将看到至少两个调用,而不会看到一个调用。

相关内容