一些编码实验(在尝试找到编码问题的较短答案时制作),带来了一些有趣的惊喜:
seq 2 | while head -n 1 ; do : ; done
输出(点击 Control-C 或者它会永远浪费CPU周期):
1
^C
相同,但使用重定向输入文件而不是管道输入:
seq 2 > two
while head -n 1 ; do : ; done < two
输出(点击 Control-C ):
1
2
^C
问题:
为什么while
循环不会阻挡seq 2 | head -n 1
的方式?
为什么重定向输入会比管道输入产生 更多 输出?
< / LI> 醇>上述代码在最近的 Lubuntu 上使用dash
和bash
进行了测试。 seq
和head
都来自 coreutils (版本 8.25-2ubuntu2 )包。
绕过(Ctrl-C)的方法:
timeout .1 sh -c "seq 2 > two ; while head -n 1 ; do : ; done < two"
1
2
timeout .1 sh -c "seq 2 | while head -n 1 ; do : ; done"
1
答案 0 :(得分:3)
head -n 1
,当在stdin上给出一个空流时,完全在其权限和规范范围内,立即以成功的退出状态退出。
因此:
seq 2 | while head -n 1 ; do : ; done
...可以合法循环,因为head -n 1
不需要退出非零状态,因此终止循环。 (如果&#34;发生错误&#34;,则只有标准才需要非零退出状态,并且行数少于请求输出的文件未定义为错误。)
确实,这是明确的:
当文件包含少于 number 行时,应将其全部复制到标准输出。这不应该是一个错误。
现在, if head
的实现,在第一次调用之后(打印第一行的内容),使文件指针在第二行的开头排队当它退出时(绝对不需要做),然后第二个循环实例将读取第二行并发出它。但是,这是一个实现细节,取决于编写head
实现的人是否选择 :
实施者完全有权根据仅在运行时可用的标准来决定遵循哪些实施。
现在,让我们说head
始终尝试一次读取8kb的块。那么,如何将指针排在第二行呢? [ * - 除了向后搜索,some implementations do在给定文件时,但标准不要求;感谢 Rob Mayhoff 这里的指针]
如果seq
的并发调用仅在第一个read
发生时写入并刷新了一行,则会发生。
显然,它是一个非常时间敏感的情况 - 竞争条件 - 并且还取决于未指定的实现细节,(seq
是否在行之间刷新其输出 - 作为{{1未指定为POSIX或任何其他标准的一部分,在平台之间是完全不同的。)