首页 > 解决方案 > bash 脚本中“jobs”命令的奇怪行为

问题描述

我对 bash 脚本比较陌生,并且对我觉得奇怪的东西有疑问。

我把它写成我的一个 bash 脚本的一部分:

sleep 10 &
while [[ $(jobs) ]]
do
        sleep 1
        echo test
        jobs &> /dev/null
done

为什么需要“工作”行?如果我把它排除在外,它将永远运行。但如果我运行:

sleep 10 & while [[ $(jobs) ]]; do sleep 1; echo test; done

直接从 bash 它可以工作。我已经在多个系统上尝试过这个。

标签: bashshellwhile-loopjobs

解决方案


有趣的观察。

发生这种情况是因为 的一个功能jobs是在作业终止时显示状态,但前提是您尚未收到通知:

$ true & sleep 1; jobs;
[1] 18687
[1]+  Done                    true

如果您每次jobs在该 shell 中再次运行时都看到“[1]+ Done”,那将是烦人且无益的。因此,jobs还将清理作业表,以便一秒钟jobs不会再次通知您:

$ true & sleep 1; jobs; echo "Here's the output the second time:"; jobs
[1] 18694
[1]+  Done                    true
Here's the output the second time:
(nothing)

现在,当您运行时$(jobs),您将创建一个子shell。由于 Unix 编程模型的工作原理,$(jobs)它是通过派生当前进程(子 shell)的相同副本来实现的,其中 stdout 连接到管道,让该进程运行jobs,然后从管道中读取结果。

这意味着jobs对作业表的任何影响都仅限于子shell。家长没有意识到您已经看到“完成”消息。

因此,每次运行时[[ $(jobs) ]],它都会向您显示“Done”消息,从而表明该声明是正确的。

添加 ajobs &> /dev/null将导致父级更新其自己的作业表,而不仅仅是子外壳的表,因此它将正确完成。


推荐阅读