无法终止循环休眠的 Bash 命令

Can't kill a Bash command that sleeps in a loop

我试过运行

$ (while true; do cat some_small_file ; sleep 1; done) | some_script

测试 some_script,但 some_script 不在我的 $PATH 中,因此打印

some_script command not found

奇怪的是 Bash 没有 return,而 Ctrl-C 什么也没做。

我什至试过用

杀死sleep
ps -u maxb | grep sleep | cut -f1 -d " " | xargs kill -9

在另一个终端中,但那当然只是继续到下一个循环迭代。

是否可以让 Bash 终止该命令?

您可以在此处采取一些方法。

一个是将 catsleep 都移动到 while 语法的条件部分,这样一旦这些命令中的任何一个不成功,循环就会失败:

while cat some_small_file && sleep 1; do :; done | some_script

一个类似的选项是将显式 break 放入循环中,(再次)以此类失败为条件:

while :; do cat some_small_file && sleep 1 || break; done | some_script

请注意 :true 的同义词。 (在我见过的每个 shell 中——不仅是 bash,甚至是 Busybox ash——它们实际上是由相同的内部函数实现的。


另请注意,此解决方案最重要的部分 是在 cat 失败时退出循环,而不是 sleep 失败时退出:在 sleep 失败将解决 kill 问题,但退出 cat 失败将处理(更有可能) some_script 已退出的情况,因此写入它会导致SIGPIPE.


顺便说一下——直接删除 ( ) 或用 { ...; } 替换它们是适当的,可以减少瞬态子 shell 的数量:虽然管道总是创建隐式 subshells,没有特别的理由使用可能(在某些情况下——有相关细节是实现而不是标准定义的)创建显式 subshell 的语法除了强制隐含的。

因此,这是一个非常小的效率改进,但对于这个答案来说并不是必需的:如果您坚持使用原始括号但以相同的方式修改流控制结构,您会得到相同的行为。