【发布时间】:2018-10-05 08:20:29
【问题描述】:
让我先介绍我的发现,然后把我的问题放在最后。 (1) 仅适用于 zsh 和 (2), (3) 适用于 zsh 和 bash。
1。命令替换的标准输入
ls | echo $(cat)
ls | { echo $(cat) }
第一个打印cat: -: Input/output error;而第二个产生ls的输出。
2。管道后的链式命令
ls | { head -n1; cat}
ls | { read a; cat}
第一个命令不能正常工作。 cat遇到EOF直接退出。但第二种形式有效:第一行被读入a,cat 得到其余部分。
3。混合标准输入
ls | { python -c 'import sys; print(sys.argv)' $(head -n1) }
ls | { python -c 'import sys; print(sys.argv); print(input())' $(head -n1) }
在第一行的{}里面,命令是打印命令行参数;在第二种形式中,该命令还从stdin 中读取一行。
由于input() 读取EOF,第一个命令可以成功运行,而第二个表单抛出。
我的问题是:
- (如第 1 节所述)带有
{}和不带有{}的表单有什么区别? - (如第 2 节)
head和cat是否可以按顺序读取相同的stdin?第二种形式如何成功,第一种形式失败? - (如第 3 节所述)命令替换中命令的
stdin如何连接到原始命令的标准输入(此处为echo)。谁先读?以及如何使stdin保持打开状态,以便两个命令(python和head)可以顺序读取相同的stdin?
【问题讨论】:
-
head -n1; cat是两个独立的命令。在那里,您在 braced-group (不是命令替换)中使用head,它在stdin上接收ls的输出,然后您有效地调用cat而不使用任何参数 - 什么你预计会发生吗? -
head获取第一行,然后cat获取其余行。也许chained这个词让你感到困惑。我以前不知道正确的词。应该是grouped? -
不,不应该分组。对于管道(例如
foo | bar | baz),每个管道将前一个命令的stdout与下一个命令的stdin连接起来。在命令之间放置行终止符';'与在脚本中包含两个单独的行相同。两者之间没有任何联系。如果你想要第一个文件ls -1 | head -n1。如果您想要除第一个以外的所有内容,那么ls -1 | tail -n+2. -
@david:在
produce_data | { head -n1; cat}中,我希望head读取输入的开头,可能是8k 左右,输出第一行并退出。cat不带参数将读取标准输入中剩余的内容并将其打印到标准输出。如果我执行一个函数head_plus (){ head -n1; cat; },我会期待同样的结果。从这个意义上说,括号中的命令确实有一个连接,因为它们的读取与输入相同。不幸的是,head是一个贪婪的虫子,读取的内容不止一行,因此 cat 剩下的输入更少。你预计会发生什么? -
我用不同的
xxx尝试了这个seq 1 xxx | { head -n1; cat; },cat从第 1861 行开始打印,seq 1 1861 | wc告诉它确实是 8198 字节。但是seq 1 2000 | { head -n1; head -n1; }只输出一行,第二行head什么也得不到。