![为什么 while 循环被挂起后就停止了?](https://linux22.com/image/78245/%E4%B8%BA%E4%BB%80%E4%B9%88%20while%20%E5%BE%AA%E7%8E%AF%E8%A2%AB%E6%8C%82%E8%B5%B7%E5%90%8E%E5%B0%B1%E5%81%9C%E6%AD%A2%E4%BA%86%EF%BC%9F.png)
为什么使用 bash 并暂停 while 循环,循环在恢复后停止?下面的简短示例。
$ while true; do echo .; sleep 1; done
.
.
^Z
[1]+ Stopped sleep 1
$ fg
sleep 1
$
我熟悉信号,我猜这可能是 bash 的自然行为,但我想更好地理解为什么它会以这种特定的方式表现。
答案1
这看起来像是几个 shell 中的错误,但它按预期工作克什93和桀骜。
背景:
大多数 shell 似乎在主 shell 内运行 while 循环,并且
伯恩壳牌如果您使用非登录 shell 键入 ^Z,则挂起整个 shell
巴什仅暂停sleep
,然后离开 while 循环,转而打印新的 shell 提示符
短跑使该命令不可暂停
和克什93,事情的工作方式非常不同:
克什93第一次启动该命令时,会执行相同的操作,但与sleep
ksh93 中的一个内置程序一样,ksh93 有一个处理程序,该处理程序会导致 while 循环分叉主 shell,然后在您键入 ^Z 时挂起。
如果你在克什93稍后输入fg
,仍然运行循环的分叉子进程将继续。
比较 bash 和 ksh93 的作业控制消息时,您会发现主要区别:
巴什报告:
[1]+ Stopped sleep 1
但克什93报告:
^Z[1] + Stopped while true; do echo .; sleep 1; done
桀骜行为类似于克什93
对于这两个 shell,只要您不键入 ^Z,您就会有一个进程(主 shell),而在您键入 ^Z 后就会有两个 shell 进程。
答案2
我写信给 Bash 的一位合著者讨论这个问题,以下是他的回复:
这并不是一个真正的错误,但它确实是一个警告。
这里的想法是挂起进程,这是与 shell 命令不同的粒度单位。当一个进程被挂起时,它返回到 shell(具有非零状态,当您停止循环测试的进程时,这会产生后果),它有一个选择:它可以跳出或继续循环,留下停止的进程。 Bash 选择(并且一直选择)在作业停止时跳出循环。继续循环很少是您想要的。
其他一些 shell 会执行一些操作,例如当进程因 SIGTSTP 而暂停时分叉 shell 的副本,并停止该进程。 Bash 从未这样做过——它似乎比利益保证更复杂——但如果有人想将该代码作为补丁提交,我会考虑合并这些更改。
因此,如果有人想要提交补丁,请使用手册页中找到的电子邮件地址。