如何检查后台作业是不是存在? (重击)
Posted
技术标签:
【中文标题】如何检查后台作业是不是存在? (重击)【英文标题】:How to check whether a background job is alive? (bash)如何检查后台作业是否存在? (重击) 【发布时间】:2012-06-29 16:01:24 【问题描述】:我有以下 bash 脚本,我们可以称之为script1.sh
:
#!/bin/bash
exec ./script2.sh &
sleep 5
if job1 is alive then #<--- this line is pseudo-code!
exec ./script3.sh &
wait
fi
可以看出,脚本将script2.sh
作为后台作业执行,然后等待5 秒(因此script2.sh
可以做一些初始化工作)。如果初始化成功,script2.sh
这个job还是会存活的,这种情况下我也想同时启动script3.sh
;如果没有,我只想退出。
但是,我不知道如何检查第一个作业是否还活着,因此是伪代码行。那么,应该用什么来代替它呢?
【问题讨论】:
运行 exec 不会像你想的那样。它将用新进程替换当前进程;将无法到达脚本中的后面几行。 【参考方案1】:您可以使用$!
获取最近的后台作业的 PID。然后,您可以检查 ps 的退出状态以确定该特定 PID 是否仍在进程列表中。例如:
sleep 30 &
if ps -p $! >&-; then
wait $!
else
jobs
fi
【讨论】:
那个确切的命令给了我错误 ps: write error: Bad Filedescriptor 这并不总是有效。例如,在 Alpine Linux 中,默认的“ps”绑定到 BusyBox,它不支持 -p 开关。使用像jobs
这样的 bash
内置函数更便携。
我从>&-
得到一个“ps:写入错误:错误的文件描述符”,这似乎是因为M>&-
中没有数字文件描述符M
关闭文件描述符M
。我改用>/dev/null 2&>1
。
或者检查pid是否存在于/proc dir exec ./script2.sh &; pid=$!; [[ -e /proc/$pid ]] && yor_code;
@EltonCarvalho,谢谢,将其添加为答案。【参考方案2】:
您可以检查信号是否可交付
./script2 &
myPid=$!
sleep 5
if kill -0 "$myPid"; then
script3 &
wait
fi
【讨论】:
【参考方案3】:要扩展 fduff 的答案,您可以使用 jobs
内置函数:
if jobs %%; then
exec ./script3.sh &
wait
fi
jobs %%
打印最近的后台进程(“当前作业”)的作业 ID,成功时返回 0,如果没有此类作业,则返回 1。
【讨论】:
Todd A. Jacobs 的方法在我的 Ubuntu 18.04 系统 (Bad file descriptor
) 上失败并且 ormaaj 的工作,但 kill -0
可能会失败(即,非零返回码),原因有两个:你不'没有权限或 PID 没有运行。 AFAIK,jobs
是一个“更干净”(奥卡姆剃刀)的答案,因为(1)它可以工作,(2)“失败”不取决于您的权限,而是取决于 PID 未运行,从而减少了您的错误检查代码需要写。
如果您只需要检查一项后台作业,这可以正常工作。此外,如果您在带有 unshare 的 PID 命名空间中运行脚本,这也是一个简单的解决方案。在后一种情况下 $!将返回命名空间内的 PID 和 ps -p $!不会在 pid 列表中找到它。对于这种情况,我还没有(还)找到简单的替代方案。
@mellow-yellow 我们必须超越记录在案的错误。对于大多数用途,权限失败在逻辑上是不可能的。如果您将作业说明符而不是 PID 传递给kill
,则您消除了由于 PID 重用而使自己进入另一个用户进程的竞争条件的可能性。我什至不知道您有任何方式无权向您自己的子进程发出信号。也就是说,我同意如果您想最大限度地正确,正确使用jobs
(假设它对于用例来说足够便携)可能会更好。【参考方案4】:
我不确定 exec 是否适用于背景,因为它会将父进程的图像替换为子进程的图像,否则,如果我们假设您摆脱了 exec,您会想要类似的东西:
#!/bin/bash
./script2.sh&
pid1=$!
if kill -0 $pid1; then
./script3.sh&
pid3=$!
wait
fi
【讨论】:
您应该尽可能使用作业说明符而不是 PID 以获得更高的可靠性:kill -0 %1
用于第一个作业,kill -0 %%
用于最近生成的作业,等等。(关键限制是您必须知道作业编号或说明符是什么,在某些脚本中,在您启动后台作业的位置可能比 PID 更难知道或预测。)
如果它更难使用你为什么说我应该使用它?
答案就在我的第一句话中:“为了更高的可靠性”。一个更合适的问题是“它以什么方式提高可靠性?”。我也没有说它更难使用。我说过在某些情况下可能更难使用。但“为了更高的可靠性”的逻辑含义是,实际上更难正确地使用 PID,或者以能够获得与工作规范相同的可靠性的方式使用 PID。对于 PID,PID 重新分配存在竞争条件。不太可能,但我们必须考虑如果这样做会对我们的脚本或用户造成什么后果。
实际上,经过深思熟虑后,我想我想把我的主张退回一点:如果您在启动子进程和使用kill
检查 PID 之间从未调用过wait
,那么你应该是安全的。因为子进程(但不是孙子进程或除我们进程的直接子进程之外的任何其他进程等)的 PID 不能被外部活动从我们下面重用,直到我们收集了它的退出状态带有wait
。【参考方案5】:
将您的后台进程 pid 复制到 var 中
./script2.sh &; pid=$!
然后检查/proc
目录中是否存在这个pid
[[ -e /proc/$pid ]] && your_code;
或ls
ls /proc/$pid 2>/dev/null && your_code;
【讨论】:
【参考方案6】:看看jobs
命令;它列出了所有正在运行的作业。
【讨论】:
以上是关于如何检查后台作业是不是存在? (重击)的主要内容,如果未能解决你的问题,请参考以下文章