等待进程完成
Bash 中是否有任何内置功能可以等待进程完成?
wait
命令只允许等待子进程完成。 我想知道是否有任何方法可以在继续执行任何脚本之前等待任何进程完成。
执行此操作的机械方法如下,但我想知道 Bash 中是否有任何内置功能。
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
Is there any builtin feature in Bash to wait for a process to finish?
The wait
command only allows one to wait for child processes to finish.
I would like to know if there is any way to wait for any process to finish before proceeding in any script.
A mechanical way to do this is as follows but I would like to know if there is any builtin feature in Bash.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
在像 OSX 这样的系统上,您可能没有 pgrep,因此您可以在按名称查找进程时尝试此方法:
进程名称末尾的
$
符号确保 grep 仅匹配 process_name 到末尾ps 输出中的行而不是其本身。On a system like OSX you might not have pgrep so you can try this appraoch, when looking for processes by name:
The
$
symbol at the end of the process name ensures that grep matches only process_name to the end of line in the ps output and not itself.等待任何进程完成
Linux(在 Alpine 上不起作用,其中 ash 不支持
tail --pid
):Darwin(要求
$pid
已打开文件):超时(秒)
Linux:
Darwin(要求
$pid
有打开的文件):To wait for any process to finish
Linux (doesn't work on Alpine, where ash doesn't support
tail --pid
):Darwin (requires that
$pid
has open files):With timeout (seconds)
Linux:
Darwin (requires that
$pid
has open files):没有内置的。 在循环中使用
kill -0
以获得可行的解决方案:或者作为更简单的 oneliner 以方便一次性使用:
正如几位评论员所指出的,如果您想等待您没有权限的进程要发送信号,您必须找到其他方法来检测进程是否正在运行来替换
kill -0 $pid
调用。 在 Linux 上,test -d "/proc/$pid"
可以工作,在其他系统上,您可能必须使用pgrep
(如果可用)或类似ps | 的东西。 grep“^$pid”
。There's no builtin. Use
kill -0
in a loop for a workable solution:Or as a simpler oneliner for easy one time usage:
As noted by several commentators, if you want to wait for processes that you do not have the privilege to send signals to, you have find some other way to detect if the process is running to replace the
kill -0 $pid
call. On Linux,test -d "/proc/$pid"
works, on other systems you might have to usepgrep
(if available) or something likeps | grep "^$pid "
.我发现如果进程由 root(或其他)拥有,“kill -0”不起作用,因此我使用 pgrep 并提出:
这可能具有可能匹配僵尸进程的缺点。
I found "kill -0" does not work if the process is owned by root (or other), so I used pgrep and came up with:
This would have the disadvantage of probably matching zombie processes.
如果进程不存在或者是僵尸进程,则该 bash 脚本循环结束。
编辑:上面的脚本给出如下< /a> 作者:Rockallite。 谢谢!
我下面的原始答案适用于 Linux,依赖于
procfs
即/proc/
。 我不知道它的可移植性:它不仅限于shell,而且操作系统本身没有系统调用来监视非子进程终止。
This bash script loop ends if the process does not exist, or it's a zombie.
EDIT: The above script was given below by Rockallite. Thanks!
My orignal answer below works for Linux, relying on
procfs
i.e./proc/
. I don't know its portability:It's not limited to shell, but OS's themselves do not have system calls to watch non-child process termination.
FreeBSD 和 Solaris 有这个方便的
pwait(1)
实用程序,它完全可以满足您的需求。我相信,其他现代操作系统也有必要的系统调用(例如,MacOS 实现了 BSD 的
kqueue
),但并非所有操作系统都可以从命令行使用它。FreeBSD and Solaris have this handy
pwait(1)
utility, which does exactly, what you want.I believe, other modern OSes also have the necessary system calls too (MacOS, for example, implements BSD's
kqueue
), but not all make it available from command-line.来自 bash 联机帮助页
From the bash manpage
所有这些解决方案都在 Ubuntu 14.04 中进行了测试:
解决方案 1(通过使用 ps 命令):
为了补充 Pierz 的答案,我建议:
在这种情况下,grep -vw grep 确保 grep 仅匹配 process_name 而不是 grep 本身。 它的优点是支持 process_name 不在
ps axg
行尾的情况。解决方案 2(使用 top 命令和进程名称):
将
process_name
替换为top -n 1 -b
中出现的进程名称。 请保留引号。要查看等待完成的进程列表,您可以运行:
解决方案 3(通过使用 top 命令和进程 ID):
将
process_id
替换为进程您的程序的 ID。All these solutions are tested in Ubuntu 14.04:
Solution 1 (by using ps command):
Just to add up to Pierz answer, I would suggest:
In this case,
grep -vw grep
ensures that grep matches only process_name and not grep itself. It has the advantage of supporting the cases where the process_name is not at the end of a line atps axg
.Solution 2 (by using top command and process name):
Replace
process_name
with the process name that appears intop -n 1 -b
. Please keep the quotation marks.To see the list of processes that you wait for them to be finished, you can run:
Solution 3 (by using top command and process ID):
Replace
process_id
with the process ID of your program.好吧,看来答案是——不,没有内置工具。
将
/proc/sys/kernel/yama/ptrace_scope
设置为0
后,就可以使用strace
程序了。 可以使用更多开关使其保持沉默,以便它真正被动等待:Okay, so it seems the answer is -- no, there is no built in tool.
After setting
/proc/sys/kernel/yama/ptrace_scope
to0
, it is possible to use thestrace
program. Further switches can be used to make it silent, so that it really waits passively:遇到了同样的问题,我解决了杀死进程然后等待每个进程使用 PROC 文件系统完成的问题:
Had the same issue, I solved the issue killing the process and then waiting for each process to finish using the PROC filesystem:
阻塞解决方案
在循环中使用
wait
,用于等待终止所有进程:当所有进程终止时,该函数将立即退出。 这是最有效的解决方案。
非阻塞解决方案
在循环中使用
kill -0
,等待终止所有进程+在检查之间执行任何操作:反应时间减少到
睡眠
时间,因为必须防止 CPU 使用率过高。实际用法:
等待终止所有进程+通知用户所有正在运行的PID。
注释
这些函数通过
$@
作为 BASH 数组的参数获取 PID。Blocking solution
Use the
wait
in a loop, for waiting for terminate all processes:This function will exits immediately, when all processes was terminated. This is the most efficient solution.
Non-blocking solution
Use the
kill -0
in a loop, for waiting for terminate all processes + do anything between checks:The reaction time decreased to
sleep
time, because have to prevent high CPU usage.A realistic usage:
Waiting for terminate all processes + inform user about all running PIDs.
Notes
These functions getting PIDs via arguments by
$@
as BASH array.没有内置功能可以等待任何进程完成。
您可以将
kill -0
发送到任何找到的 PID,这样您就不会被僵尸和在ps
中仍然可见的东西所困扰(同时仍然检索 PID 列表)使用ps
)。There is no builtin feature to wait for any process to finish.
You could send
kill -0
to any PID found, so you don't get puzzled by zombies and stuff that will still be visible inps
(while still retrieving the PID list usingps
).如果您需要终止进程并等待其完成,可以使用
killall(1)
(基于进程名称)和start-stop-daemon(8)
(基于 pidfile)。终止与
someproc
匹配的所有进程并等待它们终止:(不幸的是,对于特定的特定进程,没有
--wait
与kill
的直接等效项PID)。使用信号
SIGINT
终止基于 pidfile/var/run/someproc.pid
的进程,同时使用SIGKILL
等待它完成20 秒超时后发送,使用:If you need to both kill a process and wait for it finish, this can be achieved with
killall(1)
(based on process names), andstart-stop-daemon(8)
(based on a pidfile).To kill all processes matching
someproc
and wait for them to die:(Unfortunately, there's no direct equivalent of
--wait
withkill
for a specific pid).To kill a process based on a pidfile
/var/run/someproc.pid
using signalSIGINT
, while waiting for it to finish, withSIGKILL
being sent after 20 seconds of timeout, use:当进程终止时,使用 inotifywait 监视某些关闭的文件。 示例(在 Linux 上):
-e 指定要等待的事件,-q 表示仅在终止时最小输出。 在这种情况下,它将是:
单个 wait 命令可用于等待多个进程:
inotifywait 的输出字符串将告诉您哪个进程终止。 这只适用于“真实”文件,不适用于 /proc/ 中的内容
Use inotifywait to monitor some file that gets closed, when your process terminates. Example (on Linux):
-e specifies the event to wait for, -q means minimal output only on termination. In this case it will be:
A single wait command can be used to wait for multiple processes:
The output string of inotifywait will tell you, which process terminated. This only works with 'real' files, not with something in /proc/
Rauno Palosaari 的
Timeout in Seconds
Darwin
解决方案对于没有 GNUtail
的类 UNIX 操作系统来说是一个很好的解决方法(它不是具体到达尔文
)。 但是,根据类 UNIX 操作系统的年龄,提供的命令行比必要的更复杂,并且可能会失败:在至少一个旧的 UNIX 上,
lsof
参数+ r 1m%s
失败(即使对于超级用户):m%s
是输出格式规范。 更简单的后处理器不需要它。 例如,以下命令在 PID 5959 上等待最多五秒:在本示例中,如果 PID 5959 在五秒过去之前自行退出,则
${?}
为0
。 如果不是,${?}
将在五秒后返回1
。值得注意的是,在
+r 1
中,1
是轮询间隔(以秒为单位),因此可以根据情况进行更改。Rauno Palosaari's solution for
Timeout in Seconds
Darwin
, is an excellent workaround for a UNIX-like OS that does not have GNUtail
(it is not specific toDarwin
). But, depending on the age of the UNIX-like operating system, the command-line offered is more complex than necessary, and can fail:On at least one old UNIX, the
lsof
argument+r 1m%s
fails (even for a superuser):The
m%s
is an output format specification. A simpler post-processor does not require it. For example, the following command waits on PID 5959 for up to five seconds:In this example, if PID 5959 exits of its own accord before the five seconds elapses,
${?}
is0
. If not${?}
returns1
after five seconds.It may be worth expressly noting that in
+r 1
, the1
is the poll interval (in seconds), so it may be changed to suit the situation.