'虽然头 - 恩1'的好奇心

时间:2016-06-16 13:56:40

标签: bash while-loop posix sh unix-head

一些编码实验(在尝试找到编码问题的较短答案时制作),带来了一些有趣的惊喜:

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

问题:

  1. 为什么while循环不会阻挡seq 2 | head -n 1的方式?

  2. 为什么重定向输入会比管道输入产生 更多 输出?

    < / LI>

    上述代码在最近的 Lubuntu 上使用dashbash进行了测试。 seqhead都来自 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

1 个答案:

答案 0 :(得分:3)

head -n 1,当在stdin上给出一个空流时,完全在其权限和规范范围内,立即以成功的退出状态退出。

因此:

seq 2 | while head -n 1 ; do : ; done

...可以合法循环,因为head -n 1不需要退出非零状态,因此终止循环。 (如果&#34;发生错误&#34;,则只有标准才需要非零退出状态,并且行数少于请求输出的文件未定义为错误。)

确实,这是明确的:

  

当文件包含少于 number 行时,应将其全部复制到标准输出。这不应该是一个错误。

现在, if head的实现,在第一次调用之后(打印第一行的内容),使文件指针在第二行的开头排队当它退出时(绝对不需要做),然后第二个循环实例将读取第二行并发出它。但是,这是一个实现细节,取决于编写head实现的人是否选择

  1. 读取一个积极的大块,但只发出一个子集。 (实施效率更高。)
  2. 逐个字符循环,只消耗一行。
  3. 实施者完全有权根据仅在运行时可用的标准来决定遵循哪些实施。

    现在,让我们说head 始终尝试一次读取8kb的块。那么,如何将指针排在第二行呢? [ * - 除了向后搜索,some implementations do在给定文件时,但标准不要求;感谢 Rob Mayhoff 这里的指针]

    如果seq的并发调用仅在第一个read发生时写入并刷新了一行,则会发生

    显然,它是一个非常时间敏感的情况 - 竞争条件 - 并且还取决于未指定的实现细节,(seq是否在行之间刷新其输出 - 作为{{1未指定为POSIX或任何其他标准的一部分,在平台之间是完全不同的。)