为什么 while 循环被挂起后就停止了?

为什么 while 循环被挂起后就停止了?

为什么使用 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第一次启动该命令时,会执行相同的操作,但与sleepksh93 中的一个内置程序一样,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 从未这样做过——它似乎比利益保证更复杂——但如果有人想将该代码作为补丁提交,我会考虑合并这些更改。

因此,如果有人想要提交补丁,请使用手册页中找到的电子邮件地址。

相关内容