我知道这是一个无用的命令,但我想了解为什么,无论是在bash
或中zsh
,当我输入 时cat | ls
,cat
都会提示我输入,但只会在一行后返回,而例如</dev/stdin tr -d 'e' | ls
会让我输入不同的行,直到我点击Ctrl + D
?
答案1
与此仅在 1 秒后打印任何内容的原因相同:
(echo abc; sleep 1; echo def) | tr -d e |cat
和标准输出重定向到管道,最多实用程序开始缓冲输出,并且只有在拥有完整的数据块后才在那里写入任何内容。 (块的大小是一个实现细节,可能是几千字节。)您可以使用一些实用程序来禁用缓冲,请参阅:关闭管道中的缓冲。
但有些实现cat
不做缓冲,而是立即写入。这至少包括 GNU 和 Busybox 实现。 plaincat
对缓冲的作用是POSIX 未指定,只有cat -u
,防止缓冲。
在这里,自从ls
没有读到任何内容标准输入因此,管道的完成和退出速度可能比您键入任何内容的速度都要快。因此,当cat
/tr
开始写入任何内容时,管道已经关闭,写入者收到 SIGPIPE 并退出。由于cat
此处立即写入其读取的内容而无需缓冲,因此它会在第一个输入行之后立即获取信号。另一方面,由于tr
等待获得完整的缓冲区来写入任何内容,因此第一个输入行不会触发它。如果您输入了足够的数据,tr
最终也会将其写入管道,获取信号并退出。
就像你说的,管道 tols
是愚蠢的,因为它不读取任何内容。您可以使用类似true
或之类的东西false
来代替。
答案2
cat
不带参数将从 stdin 读取,等待输入第一行当引用交互式设备时,stdin 是行缓冲的,并将其输出到其标准输出,该标准输出被重定向到 的标准输入ls
。ls
根本不从标准输入读取,因此它只会将文件列表输出到标准输出并退出。由于ls
管道的 -end 被ls
(cat
的 stdout) 关闭,cat
因此也将退出。
对于任何不从 stdin 读取并输出到 stdout 的程序,都可以观察到相同的行为。例如:
cat | uname -a
笔记: </dev/stdin
是多余的。它将把标准输入重定向到标准输入。