等待"任何过程"完成

Bis*_*Das 133 bash scripting process wait

bash中是否有任何内置功能可以等待任何进程完成?该wait命令仅允许等待子进程完成.我想知道在继续执行任何脚本之前是否有任何方法可以等待任何进程完成.

这样做的机械方法如下,但我想知道bash中是否有任何内置功能.

while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
Run Code Online (Sandbox Code Playgroud)

Rau*_*ari 114

等待任何进程完成

Linux的:

tail --pid=$pid -f /dev/null
Run Code Online (Sandbox Code Playgroud)

达尔文(要求$pid打开文件):

lsof -p $pid +r 1 &>/dev/null
Run Code Online (Sandbox Code Playgroud)

超时(秒)

Linux的:

timeout $timeout tail --pid=$pid -f /dev/null
Run Code Online (Sandbox Code Playgroud)

达尔文(要求$pid打开文件):

lsof -p $pid +r 1m%s -t | grep -qm1 $(date -v+${timeout}S +%s 2>/dev/null || echo INF)
Run Code Online (Sandbox Code Playgroud)

  • 谁会知道`tail`会这样做. (33认同)
  • `tail` 通过使用 `kill(pid, SIG_0)` 轮询一个进程(使用 `strace` 发现)在幕后工作。 (6认同)
  • 请注意,lsof使用轮询,而“ + r 1”是超时,我个人正在寻找不使用轮询的MacOS解决方案。 (2认同)
  • @AlexanderMills,如果你能容忍你的 macOS 系统不会在命令执行时进入睡眠状态,`caffeinate -w $pid` 就能解决问题。 (2认同)

Ted*_*ddy 77

没有内置.使用kill -0在一个可行的解决方案的循环:

anywait(){

    for pid in "$@"; do
        while kill -0 "$pid"; do
            sleep 0.5
        done
    done
}
Run Code Online (Sandbox Code Playgroud)

或者作为一个简单的oneliner,便于一次性使用:

while kill -0 PIDS 2> /dev/null; do sleep 1; done;
Run Code Online (Sandbox Code Playgroud)

正如几位评论员所指出的,如果您想等待没有权限发送信号的进程,您可以找到一些其他方法来检测进程是否正在运行以替换该kill -0 $pid调用.在Linux上,test -d "/proc/$pid"可以在其他系统上使用pgrep(如果可用)或类似的东西ps | grep "^$pid ".

  • 这种解决方案不会有竞争条件吗?在"睡眠0.5"中睡觉时,使用"$ pid"的过程可能会死亡,并且可能会使用相同的"$ pid"创建另一个过程.我们最终将使用相同的`$ pid`等待2个不同的进程(甚至更多). (4认同)
  • PID通常不是按顺序生成的吗?计数在一秒钟内包裹的可能性是多少? (4认同)
  • **注意**:这并不总是有效,如[下面指出](http://stackoverflow.com/a/10407912/780703)[mp3foley](http://stackoverflow.com/users/231760/ mp3foley).有关详细信息,请参阅该评论和[我的](http://stackoverflow.com/a/11719943/780703). (2认同)
  • **警告2**(关于僵尸):上面提到Teddy的后续评论还不够,因为他们可能是僵尸.有关Linux解决方案,请参阅[我的答案如下](http://stackoverflow.com/a/11719943/780703). (2认同)
  • @ ks1322是的,这段代码确实存在竞争条件. (2认同)

mp3*_*ley 51

我发现如果进程由root(或其他)拥有,"kill -0"不起作用,所以我使用了pgrep并提出:

while pgrep -u root process_name > /dev/null; do sleep 1; done
Run Code Online (Sandbox Code Playgroud)

这将具有可能匹配僵尸进程的缺点.

  • 好观察。在POSIX中,如果调用者进程没有杀死特权,则系统调用``kill(pid,sig = 0)``失败。因此,/ bin / kill -0和“ kill -0”(内置bash)在相同条件下也会失败。 (2认同)

tei*_*ura 31

如果进程不存在,或者它是僵尸,则此bash脚本循环结束.

PID=<pid to watch>
while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do
    sleep 1
done
Run Code Online (Sandbox Code Playgroud)

编辑:以上脚本以下给出Rockallite.谢谢!

我的orignal答案适用于Linux,依赖于procfsie /proc/.我不知道它的便携性:

while [[ ( -d /proc/$PID ) && ( -z `grep zombie /proc/$PID/status` ) ]]; do
    sleep 1
done
Run Code Online (Sandbox Code Playgroud)

它不仅限于shell,但OS本身没有系统调用来监视非子进程终止.

  • 或者```s s =`ps -p $ PID -os =`&& [["$ s"&&"$ s"!='Z']]; 做睡觉1; done``` (7认同)

Mik*_* T. 14

FreeBSD和Solaris有这个方便的pwait(1)实用程序,它可以完全满足您的需求.

我相信,其他现代操作系统也有必要的系统调用(例如MacOS,实现BSD kqueue),但并非所有操作系统都可以从命令行使用.

  • `> BSD和Solaris`:检查想到的三个大BSD; OpenBSD和NetBSD都没有这个功能(在他们的手册页中),只有FreeBSD,你可以轻松查看[man.openbsd.org](http://man.openbsd.org). (2认同)
  • 我希望我能多次回答这个问题. (2认同)

Cha*_*eed 9

来自bash手册页

   wait [n ...]
          Wait for each specified process and return its termination  status
          Each  n  may be a process ID or a job specification; if a
          job spec is given, all processes  in  that  job's  pipeline  are
          waited  for.  If n is not given, all currently active child processes
          are waited for, and the return  status  is  zero.   If  n
          specifies  a  non-existent  process or job, the return status is
          127.  Otherwise, the return status is the  exit  status  of  the
          last process or job waited for.
Run Code Online (Sandbox Code Playgroud)

  • 这是真的但它只能等待当前shell的子代.你不能等待**任何**过程. (55认同)

Sae*_* BK 6

所有这些解决方案都在Ubuntu 14.04中进行了测试:

解决方案1(通过使用ps命令): 只是加起来为Pierz答案,我建议:

while ps axg | grep -vw grep | grep -w process_name > /dev/null; do sleep 1; done
Run Code Online (Sandbox Code Playgroud)

在这种情况下,grep -vw grep确保grep仅匹配process_name而不匹配grep本身.它的优点是支持process_name不在行末尾的情况ps axg.

解决方案2(使用top命令和进程名称):

while [[ $(awk '$12=="process_name" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done
Run Code Online (Sandbox Code Playgroud)

替换process_name为出现的进程名称top -n 1 -b.请保留引号.

要查看等待它们完成的进程列表,您可以运行:

while : ; do p=$(awk '$12=="process_name" {print $0}' <(top -n 1 -b)); [[ $b ]] || break; echo $p; sleep 1; done
Run Code Online (Sandbox Code Playgroud)

解决方案3(使用top命令和进程ID):

while [[ $(awk '$1=="process_id" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done
Run Code Online (Sandbox Code Playgroud)

替换process_id为程序的进程ID.

  • Downvote:长的`grep -v grep`管道是一个庞大的反模式,这预示着你没有相同名称的无关进程.如果你知道PID,那么这可以适应正常工作的解决方案. (4认同)

emu*_*emu 5

好的,所以似乎答案是 - 不,没有内置工具.

设置/proc/sys/kernel/yama/ptrace_scope0,可以使用该strace程序.可以使用其他开关使其静音,以便它实际上被动地等待:

strace -qqe '' -p <PID>
Run Code Online (Sandbox Code Playgroud)


The*_*sai 3

没有内置功能可以等待任何进程完成。

您可以发送kill -0到任何找到的 PID,这样您就不会被僵尸和仍然可见的内容所困惑ps(同时仍然使用 检索 PID 列表ps)。