'while head -n 1' 好奇心
'while head -n 1' curiosities
一些编码实验,(在尝试找到编码问题的较短答案时进行)导致了一些有趣的惊喜:
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
那样停止?
为什么 重定向输入 比 [=] 产生 更多 输出43=]管道输入?
以上代码在最近的 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
head -n 1
,当在 stdin 上给定一个空流时,完全符合其权利和规范,可以立即以成功退出状态退出。
因此:
seq 2 | while head -n 1 ; do : ; done
...可以合法地永远循环,因为 head -n 1
不需要以非零状态退出并因此终止循环。 (只有 "an error occurred" 时标准才需要非零退出状态,并且文件行数少于输出请求的行数不被定义为错误)。
确实,这是明确的:
When a file contains less than number lines, it shall be copied to standard output in its entirety. This shall not be an error.
现在,if 您的 head
实现在第一次调用后(打印第一行的内容),使文件指针在当它退出时第二行的开头,(绝对不需要),然后第二个循环实例将读取第二行并发出它。然而,这又是一个实现细节,它取决于编写您的 head
实现的人是否选择 或者 :
- 读取一个非常大的块,但只发出它的一个子集。 (更有效的实施。)
- 或逐字符循环以仅消耗一行。
实施者完全有权根据仅在运行时可用的标准来决定要遵循哪些实施。
现在,假设您的 head
总是 尝试一次读取 8kb 块。那么,它怎么能让指针在第二行排队呢? [* - 除了向后搜索,当给定文件时 some implementations do,但标准不需要;感谢 Rob Mayhoff 的指点]
这可能会发生如果 seq
的并发调用在第一个 read
发生时仅写入并刷新了一行 。
显然,这是一种对时间非常敏感的情况——一种竞争条件——并且还取决于未指定的实现细节,(seq
是否刷新其行间输出——如 seq
未指定为 POSIX 或任何其他标准的一部分,在平台之间完全不同。
一些编码实验,(在尝试找到编码问题的较短答案时进行)导致了一些有趣的惊喜:
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
那样停止?为什么 重定向输入 比 [=] 产生 更多 输出43=]管道输入?
以上代码在最近的 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
head -n 1
,当在 stdin 上给定一个空流时,完全符合其权利和规范,可以立即以成功退出状态退出。
因此:
seq 2 | while head -n 1 ; do : ; done
...可以合法地永远循环,因为 head -n 1
不需要以非零状态退出并因此终止循环。 (只有 "an error occurred" 时标准才需要非零退出状态,并且文件行数少于输出请求的行数不被定义为错误)。
确实,这是明确的:
When a file contains less than number lines, it shall be copied to standard output in its entirety. This shall not be an error.
现在,if 您的 head
实现在第一次调用后(打印第一行的内容),使文件指针在当它退出时第二行的开头,(绝对不需要),然后第二个循环实例将读取第二行并发出它。然而,这又是一个实现细节,它取决于编写您的 head
实现的人是否选择 或者 :
- 读取一个非常大的块,但只发出它的一个子集。 (更有效的实施。)
- 或逐字符循环以仅消耗一行。
实施者完全有权根据仅在运行时可用的标准来决定要遵循哪些实施。
现在,假设您的 head
总是 尝试一次读取 8kb 块。那么,它怎么能让指针在第二行排队呢? [* - 除了向后搜索,当给定文件时 some implementations do,但标准不需要;感谢 Rob Mayhoff 的指点]
这可能会发生如果 seq
的并发调用在第一个 read
发生时仅写入并刷新了一行 。
显然,这是一种对时间非常敏感的情况——一种竞争条件——并且还取决于未指定的实现细节,(seq
是否刷新其行间输出——如 seq
未指定为 POSIX 或任何其他标准的一部分,在平台之间完全不同。