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

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

 $ read typing something here $ 

但是,当我通过管道(例如来自cat传递输入时, read行为会有所不同并继续运行,直到遇到第二个换行:

 $ cat | read typing first line typing second line $ 

谁能解释为什么会这样?

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

它与换行没有任何关系。

如果你使用strace运行你的命令,你会发现cat会在关闭之前收到一个SIGPIPE

 $ strace cat | read ... someOutput ... +++ killed by SIGPIPE +++ 
  1. 第一个cat命令开始运行。
  2. 然后你第一次输入内容并按Enter键
  3. 您键入的内容将通过管道传输到read
  4. cat还在跑步,等待EOF。
  5. 您输入其他内容然后点击Enter agian。
  6. 这次,它无法通过管道read ,因为没有read等待输入(它在第一个管道之后已经关闭),除非你像这样运行它:

     cat | while read line; do echo $line; done; 
  7. cat将收到一个SIGPIPE并被关闭。

当一个进程尝试写入一个没有读取器的SOCK_STREAM类型的管道(命名与否)或套接字时,它会收到一个SIGPIPE。 [1]

接收SIGPIPE发生第二个管道发生之后。

例如,考虑yes命令,因为像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()调用,但是如果你多次运行它,你将看到至少两次调用,而不是一次。