プロセスが終了するのを待つBashの組み込み機能はありますか?
wait
コマンドでは、子プロセスの終了を待つことしかできません。スクリプトを続行する前に、プロセスが終了するのを待つ方法があるかどうかを知りたいです。
これを機械的に行う方法は次のとおりですが、Bashに組み込み機能があるかどうかを知りたいと思います。
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
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)
組み込みはありません。実行可能なソリューションを得るには、ループで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 "
などを使用する必要があります。
プロセスがルート(またはその他)によって所有されている場合、「kill -0」が機能しないことがわかったため、pgrepを使用して思い付きました:
while pgrep -u root process_name > /dev/null; do sleep 1; done
これには、おそらくゾンビプロセスと一致するという欠点があります。
この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自体には、子プロセス以外のプロセスの終了を監視するシステムコールがありません。
FreeBSDとSolarisには、この便利なpwait(1)
ユーティリティがあります。
他の最新のOSにも必要なシステムコールもあります(たとえば、MacOSはBSDのkqueue
を実装しています)が、すべてがコマンドラインから利用できるわけではありません。
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.
これらのソリューションはすべて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_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
ソリューション3(topコマンドとプロセスIDを使用):
while [[ $(awk '$1=="process_id" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done
process_id
をプログラムのプロセスIDに置き換えます。
さて、答えはそうです-いいえ、組み込みのツールはありません。
/proc/sys/kernel/yama/ptrace_scope
を0
に設定した後、strace
プログラムを使用できます。さらにスイッチを使用してサイレントにすることができるため、実際に受動的に待機します。
strace -qqe '' -p <PID>
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);
}
デバッガがプロセスにアタッチするときと同じように機能します。
プロセスが終了するのを待つ組み込み機能はありません。
見つかったPIDにkill -0
を送信できるので、ps
にまだ表示されるゾンビなどに困惑することはありません(ps
を使用してPIDリストを取得します)。
同じ問題があった場合、プロセスを強制終了し、各プロセスがPROCファイルシステムの使用を完了するのを待つ問題を解決しました。
while [ -e /proc/${pid} ]; do sleep 0.1; done
OSXのようなシステムでは、pgrepがない場合があるため、名前でプロセスを検索するときにこの方法を試すことができます。
while ps axg | grep process_name$ > /dev/null; do sleep 1; done
プロセス名の最後にある$
シンボルは、grepがps出力の行末とprocess_nameのみを一致させ、それ自体を一致させないようにします。