web-dev-qa-db-ja.com

プロセスが完了するのを待ちます

プロセスが終了するのを待つBashの組み込み機能はありますか?

waitコマンドでは、子プロセスの終了を待つことしかできません。スクリプトを続行する前に、プロセスが終了するのを待つ方法があるかどうかを知りたいです。

これを機械的に行う方法は次のとおりですが、Bashに組み込み機能があるかどうかを知りたいと思います。

while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
124
Biswajyoti Das

プロセスが完了するのを待つ

Linux:

tail --pid=$pid -f /dev/null

ダーウィン($pidに開いているファイルが必要です):

lsof -p $pid +r 1 &>/dev/null

タイムアウトあり(秒)

Linux:

timeout $timeout tail --pid=$pid -f /dev/null

ダーウィン($pidに開いているファイルが必要です):

lsof -p $pid +r 1m%s -t | grep -qm1 $(date -v+${timeout}S +%s 2>/dev/null || echo INF)
104
Rauno Palosaari

組み込みはありません。実行可能なソリューションを得るには、ループでkill -0を使用します。

anywait(){

    for pid in "$@"; do
        while kill -0 "$pid"; do
            sleep 0.5
        done
    done
}

または、簡単なワンタイム使用のためのシンプルなワンライナーとして:

while kill -0 PIDS 2> /dev/null; do sleep 1; done;

いくつかのコメンテーターが述べているように、シグナルを送信する特権を持っていないプロセスを待ちたい場合、プロセスがkill -0 $pid呼び出しを置き換えるために実行されているかどうかを検出する他の方法があります。 Linuxではtest -d "/proc/$pid"が機能しますが、他のシステムではpgrep(使用可能な場合)またはps | grep "^$pid "などを使用する必要があります。

77
Teddy

プロセスがルート(またはその他)によって所有されている場合、「kill -0」が機能しないことがわかったため、pgrepを使用して思い付きました:

while pgrep -u root process_name > /dev/null; do sleep 1; done

これには、おそらくゾンビプロセスと一致するという欠点があります。

50
mp3foley

このbashスクリプトループは、プロセスが存在しないか、ゾンビの場合に終了します。

PID=<pid to watch>
while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do
    sleep 1
done

EDIT:上記のスクリプト 以下に示した by Rockallite 。ありがとう!

以下の私の最初の答えは、procfs、つまり/proc/に依存して、Linuxで機能します。移植性はわかりません。

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

シェルに限定されませんが、OS自体には、子プロセス以外のプロセスの終了を監視するシステムコールがありません。

31
teika kazura

FreeBSDとSolarisには、この便利なpwait(1)ユーティリティがあります。

他の最新のOSにも必要なシステムコールもあります(たとえば、MacOSはBSDのkqueueを実装しています)が、すべてがコマンドラインから利用できるわけではありません。

12
Mikhail T.

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.
9
Charlweed

これらのソリューションはすべてUbuntu 14.04でテストされています。

解決策1(psコマンドを使用): Pierzの答えをまとめるために、次のことをお勧めします。

while ps axg | grep -vw grep | grep -w process_name > /dev/null; do sleep 1; done

この場合、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

process_nametop -n 1 -bに表示されるプロセス名に置き換えます。引用符を保管してください。

終了するまで待機しているプロセスのリストを表示するには、次を実行できます。

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

ソリューション3(topコマンドとプロセスIDを使用):

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

process_idをプログラムのプロセスIDに置き換えます。

5
Saeid BK

さて、答えはそうです-いいえ、組み込みのツールはありません。

/proc/sys/kernel/yama/ptrace_scope0に設定した後、straceプログラムを使用できます。さらにスイッチを使用してサイレントにすることができるため、実際に受動的に待機します。

strace -qqe '' -p <PID>
4
emu

PIDで待機し、PIDが死んだときにすぐに戻る小さなユーティリティを見つけました。

https://github.com/izabera/waiter

Gccでコンパイルできる小さなCファイルです。

#define _GNU_SOURCE
#include <sys/ptrace.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
  if (argc == 1) return 1;
  pid_t pid = atoi(argv[1]);
  if (ptrace(PTRACE_SEIZE, pid, NULL, NULL) == -1) return 1;
  siginfo_t sig;
  return waitid(P_PID, pid, &sig, WEXITED|WNOWAIT);
}

デバッガがプロセスにアタッチするときと同じように機能します。

4
Mark L. Smith

プロセスが終了するのを待つ組み込み機能はありません。

見つかったPIDにkill -0を送信できるので、psにまだ表示されるゾンビなどに困惑することはありません(psを使用してPIDリストを取得します)。

2
TheBonsai

同じ問題があった場合、プロセスを強制終了し、各プロセスがPROCファイルシステムの使用を完了するのを待つ問題を解決しました。

while [ -e /proc/${pid} ]; do sleep 0.1; done
2
littlebridge

OSXのようなシステムでは、pgrepがない場合があるため、名前でプロセスを検索するときにこの方法を試すことができます。

while ps axg | grep process_name$ > /dev/null; do sleep 1; done

プロセス名の最後にある$シンボルは、grepがps出力の行末とprocess_nameのみを一致させ、それ自体を一致させないようにします。

0
Pierz