프로세스가 끝날 때까지 기다리십시오


147

Bash에 프로세스가 완료 될 때까지 기다리는 내장 기능이 있습니까?

wait명령은 자식 프로세스가 완료 될 때까지 기다릴 수 있습니다. 스크립트를 진행하기 전에 프로세스가 완료 될 때까지 기다리는 방법이 있는지 알고 싶습니다.

이를 수행하는 기계적 방법은 다음과 같지만 Bash에 내장 기능이 있는지 알고 싶습니다.

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

4
나에게주게 두주의 사항 : 1.으로는 아래 지적 에 의해 mp3foley , "살인은 -0"POSIX 항상 일을하지 않습니다. 2. 또한 프로세스가 좀비가 아닌 프로세스가 사실상 종료 된 프로세스인지 확인하려고합니다. 자세한 내용은 mp3foley의 의견광산 을 참조하십시오.
teika kazura

2
또 다른주의 ( 원래는 지적 에 의해 ks1322 아래) : 자식 프로세스보다 PID 다른 사용은 강력하지 않습니다. 안전한 방법을 원하면 IPC를 사용하십시오.
teika kazura

답변:


138

프로세스가 완료 될 때까지 기다리려면

리눅스 :

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

다윈 ( $pid파일을 열어야 함) :

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

시간 초과 (초)

리눅스 :

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)

42
누가 그렇게했는지 알았을 것 tail입니다.
ctrl-alt-delor

8
tailkill(pid, SIG_0)프로세스 로 폴링하여 후드에서 작동 합니다 (를 사용하여 발견 strace).
Att Righ

2
lsof는 폴링을 사용한다는 점에 유의하십시오. 즉 +r 1, 시간 초과입니다. 개인적으로 폴링을 사용하지 않는 MacOS 솔루션을 찾고 있습니다.
Alexander Mills

1
이 속임수 는 좀비에게는 실패 합니다. 죽일 수없는 프로세스는 괜찮습니다. tail라인이 kill (pid, 0) != 0 && errno != EPERM있습니다.
teika kazura

2
@AlexanderMills, 명령이 실행될 때 잠들지 않는 macOS 시스템을 견딜 수 있으면 caffeinate -w $pid트릭을 수행합니다.
zneak

83

내장이 없습니다. kill -0실행 가능한 솔루션을 위해 루프에서 사용하십시오 .

anywait(){

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

또는 한 번 사용하기 쉬운 더 간단한 oneliner로 :

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

여러 주석 작성자가 언급 한 것처럼 신호를 보낼 권한이없는 프로세스를 기다리려면 kill -0 $pid통화 를 대체하기 위해 프로세스가 실행 중인지 감지하는 다른 방법을 찾으십시오 . Linux에서 test -d "/proc/$pid"작동하면 다른 시스템에서 (사용 pgrep가능한 경우) 또는 이와 유사한 것을 사용해야 할 수도 있습니다 ps | grep "^$pid ".


2
주의 : 아래 에서 mp3foley가 지적한 것처럼 항상 작동하지는 않습니다 . 자세한 내용은 해당 의견과 광산 을 참조하십시오.
teika kazura 2016

2
주의 2 (좀비에서) : 위의 Teddy의 후속 코멘트는 좀비 일 수 있으므로 아직 충분하지 않습니다. Linux 솔루션에 대해서는 아래 답변을 참조하십시오 .
teika kazura

4
이 솔루션이 경쟁 조건에 위험하지 않습니까? 잠자는 동안 sleep 0.5프로세스가 종료 $pid되고 다른 프로세스가 동일한 프로세스로 생성 될 수 있습니다 $pid. 그리고 우리는 같은 두 개의 다른 프로세스 (또는 그 이상)를 기다릴 것 $pid입니다.
ks1322

2
@ ks1322 예,이 코드에는 실제로 경쟁 조건이 있습니다.
Teddy

4
PID는 일반적으로 순차적으로 생성되지 않습니까? 1 초 안에 카운트가 줄어드는 가능성은 무엇입니까?
esmiralha

53

프로세스가 루트 (또는 다른) 소유인 경우 "kill -0"이 작동하지 않는다는 것을 알았으므로 pgrep을 사용하여 다음을 수행했습니다.

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

이것은 아마도 좀비 프로세스를 일치시키는 단점이 있습니다.


2
좋은 관찰. POSIX kill(pid, sig=0)에서 호출자 프로세스에 강제 종료 권한이 없으면 시스템 호출 이 실패합니다. 따라서 / bin / kill -0과 "kill -0"(bash 내장)도 동일한 조건에서 실패합니다.
teika kazura

31

프로세스가 존재하지 않거나 좀비 인 경우이 bash 스크립트 루프가 종료됩니다.

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

편집 : 위의 스크립트 Rockallite에 의해 아래주어 졌습니다 . 감사!

아래의 저의 정답은 Linux에서 작동하며 procfsie에 의존합니다 /proc/. 이식성에 대해 잘 모르겠습니다.

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

쉘에만 국한되지는 않지만 OS 자체에는 자식 프로세스가 아닌 프로세스 종료를 감시하는 시스템 호출이 없습니다.


1
좋은데 비록 grep /proc/$PID/status큰 따옴표 ( bash: test: argument expected) 로 둘러 싸야했지만
Griddo

흠 ... 방금 다시 시도하고 작동했습니다. 지난번에 내가 잘못한 것 같아
Griddo

7
또는while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do sleep 1; done
Rockallite

1
그것에서 - 불행하게도,이 비지 박스에서 작동하지 않습니다 ps,도 -p또는 s=지원
ZimbiX

14

FreeBSD와 Solaris는이 편리한 pwait(1)유틸리티를 가지고 있습니다.

다른 현대 OS에도 필요한 시스템 호출 (예 : MacOS, BSD 구현 kqueue)도 있지만 명령 줄에서 모두 사용할 수있는 것은 아닙니다.


2
> BSD and Solaris: 떠오르는 세 가지 큰 BSD 검사. man.openbsd.org에서 쉽게 확인할 수 있듯이 OpenBSD 나 NetBSD는이 기능을 (Man 페이지에서) FreeBSD 만 가지고 있습니다.
benaryorg

당신이 옳은 것 같습니다. Mea culpa ... 그들은 모두 구현 kqueue하므로 FreeBSD를 컴파일하는 pwait(1)것은 쉽지 않습니다. 다른 BSD의 가져 오기 기능이 왜 나를 피하지
Mikhail T.

1
plink me@oracle box -pw redacted "pwait 6998";email -b -s "It's done" etc지금부터 몇 시간이 아닌 지금 집에 갈 수있게 해주었습니다.
zzxyz 1

11

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.

56
사실이지만 현재 쉘의 자식 만 기다릴 수 있습니다. 당신은 기다릴 수없는 어떤 과정.
gumik

@gumik : "n을 지정하지 않으면 현재 활성화 된 모든 자식 프로세스가 대기합니다" . 이것은 완벽하게 작동합니다. wait인수가 없으면 자식 프로세스가 끝날 때까지 프로세스가 차단됩니다 . 솔직히, 나는 기다릴 어떤 지점이 표시되지 않는 어떤 진행 systemprocesses 항상 이후 과정.
coderofsalvation

1
@coderofsalvation (sleep 10 & sleep 3 & wait)은 반환하는 데 10 초가 걸립니다. 인수없이 대기하면 모든 자식 프로세스가 완료 될 때까지 차단됩니다. 첫 번째 하위 (또는 지명 된) 프로세스가 완료되면 OP에 알림을 보내려고합니다.
android.weasel

프로세스가 백그라운드 또는 포 그라운드되지 않은 경우 (Solaris, Linux 또는 Cygwin에서) 작동하지 않습니다. 전의. sleep 1000 ctrl-z wait [sleep pid]즉시 반환
zzxyz

6

이 모든 솔루션은 Ubuntu 14.04에서 테스트되었습니다.

해결책 1 (ps 명령을 사용하여) : Pierz 답변까지 추가하려면 다음을 제안합니다.

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

이 경우 grep -vw grepgrep이 grep 자체가 아닌 process_name 과만 일치하는지 확인하십시오. process_name이에 줄 끝에 있지 않은 경우를 지원하는 이점이 ps axg있습니다.

해결 방법 2 (최고 명령 및 프로세스 이름 사용) :

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 (최고 명령 및 프로세스 ID 사용) :

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

교체 process_id프로그램의 프로세스 ID.


4
Downvote : 긴 grep -v grep파이프 라인은 방대한 반 패턴이며, 같은 이름의 관련없는 프로세스가 없다는 것을 전제로합니다. PID를 아는 경우 제대로 작동하는 솔루션에 적합 할 수 있습니다.
tripleee

의견에 감사드립니다. 어느 정도-w 의 문제를 피하기 위해 플래그 를 추가했습니다 . 또한 귀하의 의견에 따라 두 가지 솔루션을 추가했습니다. grep -v grep
Saeid BK

5

알았어요. 대답은 아닙니다. 도구가 내장되어 있지 않습니다.

설정 한 후 /proc/sys/kernel/yama/ptrace_scope0, 사용할 수 있습니다 strace프로그램. 추가 스위치를 사용하여 자동으로 설정하여 실제로 수동적으로 대기 할 수 있습니다.

strace -qqe '' -p <PID>

1
좋은 것! 두 곳의 다른 곳에서 주어진 PID에 연결할 수없는 것 같습니다 (두 Operation not permitted번째 strace 인스턴스를 얻 습니다). 확인할 수 있습니까?
eudoxos

@eudoxos 네, ptrace의 맨 페이지는 다음 (...)"tracee" always means "(one) thread"과 같이 말합니다 . 더 많은 프로세스가 이런 식으로 기다리게하려면 체인을 만들어야합니다.
emu

2

차단 솔루션

wait모든 프로세스 종료를 기다리는 동안 in 루프를 사용하십시오 .

function anywait()
{

    for pid in "$@"
    do
        wait $pid
        echo "Process $pid terminated"
    done
    echo 'All processes terminated'
}

이 기능은 모든 프로세스가 종료되면 즉시 종료됩니다. 이것이 가장 효율적인 솔루션입니다.

비 차단 솔루션

kill -0in 루프를 사용하여 모든 프로세스가 종료 될 때까지 기다리십시오.

function anywait_w_status()
{
    for pid in "$@"
    do
        while kill -0 "$pid"
        do
            echo "Process $pid still running..."
            sleep 1
        done
    done
    echo 'All processes terminated'
}

sleepCPU 사용률이 높아야하기 때문에 반응 시간이 시간으로 단축되었습니다 .

현실적인 사용법 :

모든 프로세스 종료 대기 중 및 실행중인 모든 PID 에 대해 사용자에게 알립니다 .

function anywait_w_status2()
{
    while true
    do
        alive_pids=()
        for pid in "$@"
        do
            kill -0 "$pid" 2>/dev/null \
                && alive_pids+="$pid "
        done

        if [ ${#alive_pids[@]} -eq 0 ]
        then
            break
        fi

        echo "Process(es) still running... ${alive_pids[@]}"
        sleep 1
    done
    echo 'All processes terminated'
}

노트

이 함수는 인수를 통해 PID를 $@BASH 배열로 가져 옵니다.


2

같은 문제가 발생하여 프로세스를 종료 한 다음 PROC 파일 시스템을 사용하여 각 프로세스가 완료되기를 기다리는 문제를 해결했습니다.

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

폴링은 아주 나쁜, 당신은 :) 경찰의 방문 얻을 수
알렉산더 밀스

2

프로세스가 완료 될 때까지 기다리는 기본 기능은 없습니다.

kill -0발견 된 PID로 보낼 수 있으므로 여전히 볼 수있는 좀비와 물건에 의아해하지 않습니다 ps(여전히를 사용하여 PID 목록을 검색하는 동안 ps).


1

프로세스가 종료 될 때 inotifywait를 사용하여 닫히는 파일을 모니터링하십시오. 예 (Linux) :

yourproc >logfile.log & disown
inotifywait -q -e close logfile.log

-e는 대기 할 이벤트를 지정합니다. -q는 종료시에만 최소 출력을 의미합니다. 이 경우 다음과 같습니다.

logfile.log CLOSE_WRITE,CLOSE

단일 대기 명령을 사용하여 여러 프로세스를 기다릴 수 있습니다.

yourproc1 >logfile1.log & disown
yourproc2 >logfile2.log & disown
yourproc3 >logfile3.log & disown
inotifywait -q -e close logfile1.log logfile2.log logfile3.log

inotifywait의 출력 문자열은 어떤 프로세스가 종료되었는지 알려줍니다. 이것은 / proc /의 무언가가 아닌 '실제'파일에서만 작동합니다.


0

OSX와 같은 시스템에서는 pgrep이 없을 수 있으므로 이름으로 프로세스를 찾을 때이 접근법을 시도 할 수 있습니다.

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

$프로세스 이름 끝에 있는 기호는 grep이 자체가 아니라 ps 출력의 행 끝과 process_name 만 일치하도록합니다.


끔찍한 : 명령 줄 어딘가에 그 이름을 가진 여러 프로세스가있을 수 있으며 자신의 grep이 포함되어 있습니다. 대신에 리디렉션의 /dev/null, -q사용해야합니다 grep. 루프가 잠자는 동안 프로세스의 다른 인스턴스가 시작되어 알 수 없을 것입니다.
Mikhail T.

다른 사람들이 비슷한 접근 방식을 제안한 것처럼 왜 당신 이이 대답을 '끔찍한'으로 분류했는지 잘 모르겠습니다. -q내 대답에서 언급했듯이 제안이 유효 하지만 구체적으로 종료 $수단 grep은 "명령 줄 어딘가"라는 이름과 일치하지 않으며 자체적으로 일치하지 않습니다. 실제로 OSX에서 사용해 보셨습니까?
Pierz

0

대한 라우 노는 Palosaari의 솔루션 Timeout in Seconds Darwin에 대한 훌륭한 해결책이다 GNU를 가지고 있지 않는 OS UNIX-같은 tail(이 특정되지 않습니다 Darwin). 그러나 UNIX와 유사한 운영 체제의 연령에 따라 제공되는 명령 줄은 필요 이상으로 복잡하여 실패 할 수 있습니다.

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

하나 이상의 이전 UNIX에서 lsof인수 +r 1m%s가 실패합니다 (슈퍼 유저 인 경우에도).

lsof: can't read kernel name list.

m%s출력 포맷 규격이다. 더 간단한 포스트 프로세서는 필요하지 않습니다. 예를 들어 다음 명령은 PID 5959에서 최대 5 초 동안 대기합니다.

lsof -p 5959 +r 1 | awk '/^=/ { if (T++ >= 5) { exit 1 } }'

이 예에서 PID 5959가 5 초가 경과하기 전에 자체 협정을 종료하는 경우 ${?}입니다 0. 5 초 후에도 ${?}돌아 오지 않으면1

그것은 명시한다는 점에서를 지적 가치가있을 수 있습니다 +r 1의는 1그 상황에 맞게 변경 될 수 있으므로, (초) 폴링 간격이다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.