प्रक्रिया समाप्त होने तक प्रतीक्षा करें


147

क्या बैश में कोई बिल्टइन फीचर है जो किसी प्रक्रिया के खत्म होने का इंतजार करता है?

waitआदेश केवल एक ही समाप्त करने के लिए बच्चे की प्रक्रिया के लिए प्रतीक्षा करने की अनुमति देता है। मैं जानना चाहूंगा कि क्या किसी स्क्रिप्ट में आगे बढ़ने से पहले किसी प्रक्रिया के खत्म होने का इंतजार करने का कोई तरीका है।

ऐसा करने का एक यांत्रिक तरीका इस प्रकार है, लेकिन मैं यह जानना चाहूंगा कि क्या बैश में कोई अंतर्निहित विशेषता है।

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

4
मुझे दो सावधानी देनी चाहिए : 1. जैसा कि एमपीएफोले द्वारा नीचे बताया गया है , "किल -0" हमेशा पॉसिक्स के लिए काम नहीं करता है। 2. संभवतः आप यह भी सुनिश्चित करना चाहते हैं कि प्रक्रिया एक ज़ोंबी नहीं है, जो कि वास्तव में एक समाप्त प्रक्रिया है। देखें mp3foley की टिप्पणी और मेरा जानकारी के लिए।
तैका कजुरा

2
एक और सावधानी ( मूल रूप से नीचे ks1322 द्वारा इंगित की गई है): एक बच्चे की प्रक्रिया के अलावा अन्य पीआईडी ​​का उपयोग करना मजबूत नहीं है। यदि आप एक सुरक्षित तरीका चाहते हैं, तो उदाहरण के लिए IPC का उपयोग करें।
तैका काज़ुरा

जवाबों:


139

किसी प्रक्रिया के समाप्त होने की प्रतीक्षा करने के लिए

लिनक्स:

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होगा कि वह ऐसा करेगा।
15-20 बजे ctrl-alt-delor

8
tailkill(pid, SIG_0)एक प्रक्रिया के साथ मतदान करके हुड के तहत काम करता है (खोज का उपयोग करके strace)।
आरएच

2
ध्यान दें कि lsof पोलिंग का उपयोग करता है, यानी +r 1टाइमआउट, मैं व्यक्तिगत रूप से MacOS के लिए एक समाधान की तलाश कर रहा हूं जो मतदान का उपयोग नहीं करता है।
अलेक्जेंडर मिल्स

1
यह चाल लाश के लिए विफल है। यह उन प्रक्रियाओं के लिए ठीक है जिन्हें आप मार नहीं सकते; tailलाइन है kill (pid, 0) != 0 && errno != EPERM
तैका कजुरा

2
@AlexanderMills, यदि आप अपने macOS सिस्टम को बर्दाश्त नहीं कर सकते हैं जैसे कि कमांड निष्पादित नहीं करता है, caffeinate -w $pidतो वह सोएगा ।
1

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कॉल का स्थान लेने के लिए प्रक्रिया चल रही है या नहीं, यह पता लगाने के लिए कोई और तरीका है । लिनक्स पर, test -d "/proc/$pid"काम करता है, अन्य प्रणालियों पर आपको pgrep(यदि उपलब्ध हो) या कुछ और का उपयोग करना पड़ सकता है ps | grep "^$pid "


2
सावधानी : यह हमेशा काम नहीं करता है, जैसा कि mp3foley द्वारा नीचे बताया गया है । उस टिप्पणी और विवरण के लिए मेरा देखें।
टेकिका कजुरा

2
सावधानी 2 (लाश पर): ऊपर टेडी द्वारा अनुवर्ती टिप्पणी अभी तक पर्याप्त नहीं है, क्योंकि वे लाश हो सकते हैं। लिनक्स समाधान के लिए नीचे मेरा उत्तर देखें ।
तैका काज़ुरा

4
क्या यह समाधान एक दौड़ की स्थिति को जोखिम में नहीं डालता है? सोते समय sleep 0.5, प्रक्रिया के साथ $pidमृत्यु हो सकती है और उसी के साथ एक और प्रक्रिया बनाई जा सकती है $pid। और हम एक ही के साथ 2 अलग-अलग प्रक्रियाओं (या इससे भी अधिक) की प्रतीक्षा करेंगे $pid
ks1322

2
@ ks1322 हां, इस कोड में वास्तव में एक दौड़ की स्थिति है।
टेडी

4
पीआईडी ​​आमतौर पर क्रमिक रूप से उत्पन्न नहीं होते हैं? एक सेकंड में चारों ओर लपेटने की गिनती की संभावना क्या है?
एस्मिराल्हा

53

मैंने पाया कि "किल -0" काम नहीं करता है यदि प्रक्रिया जड़ (या अन्य) के स्वामित्व में है, तो मैंने pgrep का उपयोग किया और ऊपर आया:

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

यह संभवतः मिलान ज़ोंबी प्रक्रियाओं का नुकसान होगा।


2
अच्छा अवलोकन। POSIX में, kill(pid, sig=0)यदि कॉलर प्रक्रिया को मारने का विशेषाधिकार नहीं है , तो सिस्टम कॉल विफल हो जाता है। इस प्रकार / बिन / मार -0 और "मार -0" (बाश बिल्ट-इन) भी उसी शर्त के तहत विफल हो जाते हैं।
तैका कजुरा

31

यह बैश स्क्रिप्ट लूप समाप्त होता है यदि प्रक्रिया मौजूद नहीं है, या यह एक ज़ोंबी है।

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

EDIT : उपरोक्त स्क्रिप्ट रॉकलाइट द्वारा नीचे दी गई थी । धन्यवाद!

नीचे दिए गए मेरे orignal जवाब लिनक्स के लिए काम करता है, procfsयानी पर भरोसा करते हैं /proc/। मुझे इसकी पोर्टेबिलिटी की जानकारी नहीं है:

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

यह शेल तक सीमित नहीं है, लेकिन गैर-बाल प्रक्रिया समाप्ति को देखने के लिए ओएस के स्वयं के पास सिस्टम कॉल नहीं है।


1
अच्छा है। हालाँकि मुझे grep /proc/$PID/statusदोहरे उद्धरण के साथ घेरना था ( bash: test: argument expected)
ग्रिडो

हम ... बस फिर से कोशिश की और यह काम किया। मुझे लगता है कि मैंने पिछली बार कुछ गलत किया था।
ग्रिडो

7
याwhile s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do sleep 1; done
रॉकलाईट सेप

1
दुर्भाग्य से, इस बिजीबॉक्स में काम नहीं करता है - अपने में ps, न तो -pया s=समर्थन कर रहे
ZimbiX

14

फ्रीबीएसडी और सोलारिस में यह आसान pwait(1)उपयोगिता है, जो वास्तव में आप क्या चाहते हैं।

मेरा मानना ​​है, अन्य आधुनिक ओएस में भी आवश्यक सिस्टम कॉल हैं (उदाहरण के लिए, MacOS, BSD के kqueue) को लागू करता है , लेकिन सभी इसे कमांड-लाइन से उपलब्ध नहीं कराते हैं।


2
> BSD and Solaris: मन में आने वाली तीन बड़ी बीएसडी का निरीक्षण करना; न तो OpenBSD और न ही NetBSD का यह कार्य है (उनके मैन पेज में), केवल FreeBSD करता है, जैसा कि आप man.openbsd.org पर आसानी से देख सकते हैं ।
बेनरॉर्ग

लगता है आप सही हैं। Mea culpa ... वे सभी लागू करते हैं kqueue, इसलिए FreeBSD को संकलित pwait(1)करना हालांकि तुच्छ होगा। अन्य BSD का आयात क्यों नहीं किया गया है कि फीचर मुझे बचा ले ...
मिखाइल टी।

1
plink me@oracle box -pw redacted "pwait 6998";email -b -s "It's done" etcबस मुझे अब से घंटों के बजाय घर जाने की अनुमति दी।
zzxyz

11

बैश मैनपेज से

   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: "यदि n नहीं दिया गया है, तो वर्तमान में सभी सक्रिय बाल प्रक्रियाओं का इंतजार किया जा रहा है" । यह पूरी तरह से काम करता है .. waitबिना आर्ग के प्रक्रिया को रोक देगा जब तक कि कोई भी बच्चे की प्रक्रिया पूरी नहीं हो जाती। ईमानदारी से, मैं किसी भी प्रक्रिया के लिए प्रतीक्षा करने के लिए कोई बिंदु नहीं देखता हूं क्योंकि हमेशा सिस्टमप्रोसेस चल रहा है।
कोडरफॉल्सेशन

1
@ सहसंयोजक (नींद 10 और नींद 3 और प्रतीक्षा) को वापस लौटने में 10 सेकंड लगते हैं: जब तक सभी बच्चे प्रक्रिया समाप्त नहीं कर लेते तब तक इंतजार किए बिना आर्ग को रोक दिया जाएगा। ओपी चाहता है कि जब पहला बच्चा (या नामांकित) प्रक्रिया समाप्त हो जाए तो उसे अधिसूचित किया जाए।
android.weasel

यदि प्रक्रिया पृष्ठभूमि में नहीं है या अग्रभूमि पर नहीं है (सोलारिस, लिनक्स या सिगविन पर) काम नहीं करता है। पूर्व। sleep 1000 ctrl-z wait [sleep pid]तुरंत लौटता है
zzxyz

6

इन सभी समाधानों का परीक्षण Ubuntu 14.04 में किया गया है:

समाधान 1 (पीएस कमांड का उपयोग करके): बस पियरज़ उत्तर को जोड़ने के लिए, मैं सुझाव दूंगा:

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 (शीर्ष आदेश और प्रक्रिया नाम का उपयोग करके):

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 (शीर्ष कमांड और प्रक्रिया आईडी का उपयोग करके):

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

process_idअपने प्रोग्राम की प्रोसेस आईडी से बदलें ।


4
डाउनवोट: लंबी grep -v grepपाइपलाइन एक विशाल एंटीपैटर्न है, और यह निर्धारित करता है कि आपके पास समान नाम के साथ असंबंधित प्रक्रिया नहीं है। यदि आप इसके बजाय PID को जानते हैं, तो इसे ठीक से काम करने वाले समाधान के लिए अनुकूलित किया जा सकता है।
ट्रिपल

टिप्पणी के लिए धन्यवाद ट्रिपल। मैंने कुछ हद तक-w समस्या से बचने के लिए ध्वज जोड़ा । मैंने आपकी टिप्पणी के आधार पर दो और समाधान भी जोड़े। grep -v grep
सैयद बीके जूल

5

ठीक है, तो ऐसा लगता है कि उत्तर है - नहीं, कोई उपकरण नहीं बनाया गया है।

सेट /proc/sys/kernel/yama/ptrace_scopeकरने के बाद 0, straceप्रोग्राम का उपयोग करना संभव है । आगे के स्विच का उपयोग इसे चुप करने के लिए किया जा सकता है, ताकि यह वास्तव में निष्क्रिय प्रतीक्षा करे:

strace -qqe '' -p <PID>

1
अच्छा है! हालांकि ऐसा लगता है कि दो अलग-अलग स्थानों से दिए गए पीआईडी ​​को संलग्न करना संभव नहीं है (मुझे Operation not permittedदूसरी स्ट्रेस इंस्टेंस के लिए मिलता है ); क्या आप इसकी पुष्टि कर सकते हैं?
यूडोक्सोस

@eudoxos हां, ptrace के लिए मेनपेज कहता है: (...)"tracee" always means "(one) thread"(और मैं आपके द्वारा बताई गई त्रुटि की पुष्टि करता हूं)। अधिक प्रक्रियाओं को इस तरह प्रतीक्षा करने के लिए, आपको एक श्रृंखला बनानी होगी।
इमू

2

समाधान अवरुद्ध करना

waitसभी प्रक्रियाओं को समाप्त करने की प्रतीक्षा में, लूप में उपयोग करें :

function anywait()
{

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

यह प्रक्रिया तुरंत समाप्त हो जाएगी, जब सभी प्रक्रियाओं को समाप्त कर दिया गया था। यह सबसे कुशल उपाय है।

गैर-अवरुद्ध समाधान

kill -0लूप का उपयोग करें , सभी प्रक्रियाओं को समाप्त करने के लिए प्रतीक्षा करने के लिए + चेक के बीच कुछ भी करें:

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'
}

प्रतिक्रिया समय कम हो गया sleep, क्योंकि उच्च CPU उपयोग को रोकना है।

एक यथार्थवादी उपयोग:

सभी प्रक्रियाओं को समाप्त करने की प्रतीक्षा कर रहे हैं + उपयोगकर्ता को सभी चल रहे पीआईडी ​​के बारे में सूचित करते हैं ।

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'
}

टिप्पणियाँ

ये कार्य $@BASH सरणी के रूप में तर्क के माध्यम से PID हो रहे हैं ।


2

एक ही मुद्दा था, मैंने इस प्रक्रिया को मारने वाली समस्या को हल किया और फिर PROC फाइलसिस्टम का उपयोग करके प्रत्येक प्रक्रिया के समाप्त होने की प्रतीक्षा कर रहा था:

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

मतदान बहुत बुरा है, आप पुलिस से एक यात्रा प्राप्त कर सकते हैं :)
अलेक्जेंडर मिल्स

2

किसी भी प्रक्रिया को समाप्त करने के लिए प्रतीक्षा करने के लिए कोई अंतर्निहित सुविधा नहीं है।

आप पाए kill -0गए किसी भी पीआईडी ​​को भेज सकते हैं, ताकि आप लाश और सामान से हैरान न हों, जो अभी भी ps(पीआईडी ​​सूची का उपयोग करके पुनर्प्राप्त करते समय) में दिखाई देगा ps


1

जब आपकी प्रक्रिया समाप्त हो जाती है, तो बंद होने वाली कुछ फ़ाइल की निगरानी के लिए inotifywait का उपयोग करें। उदाहरण (लिनक्स पर):

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

-ई घटना के लिए प्रतीक्षा करने के लिए निर्दिष्ट करता है, -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

$प्रक्रिया नाम सुनिश्चित के अंत में प्रतीक ग्रेप मैचों केवल ps उत्पादन में पंक्ति के अंत और खुद को नहीं करने के लिए process_name कि।


भयानक: कमांड लाइन में उस नाम के साथ कई प्रक्रियाएं हो सकती हैं , आपका अपना grep शामिल है। के लिए पुनर्निर्देशित करने के बजाय /dev/null, के -qसाथ इस्तेमाल किया जाना चाहिए grep। प्रक्रिया का एक और उदाहरण शुरू हो सकता है जब आपका लूप सो रहा था और आप कभी नहीं जान पाएंगे ...
मिखाइल टी।

मुझे यकीन नहीं है कि आपने इस उत्तर को 'भयानक' के रूप में क्यों गाया - जैसा कि दूसरों द्वारा एक समान दृष्टिकोण का सुझाव दिया गया है? जब तक -qसुझाव मान्य है, जैसा कि मैंने अपने उत्तर में उल्लेख किया है कि विशेष रूप से समाप्ति का $मतलब है कि grep "कमांड लाइन में कहीं" नाम से मेल नहीं खाएगा और न ही यह स्वयं से मेल खाएगा। क्या तुमने वास्तव में OSX पर कोशिश की है?
पियरज

0

रुनो पालोसेरी का समाधान Timeout in Seconds Darwin, UNIX जैसे OS के लिए एक उत्कृष्ट समाधान है जिसमें GNU नहीं है tail(यह विशिष्ट नहीं है Darwin)। लेकिन, UNIX- जैसी ऑपरेटिंग सिस्टम की उम्र के आधार पर, पेश की जाने वाली कमांड-लाइन आवश्यकता से अधिक जटिल है, और विफल हो सकती है:

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

कम से कम एक पुराने यूनिक्स पर, lsofतर्क +r 1m%sविफल हो जाता है (यहां तक ​​कि एक सुपरयुसर के लिए):

lsof: can't read kernel name list.

m%sएक निर्गम प्रारूप विनिर्देश है। एक सरल पोस्ट-प्रोसेसर को इसकी आवश्यकता नहीं है। उदाहरण के लिए, निम्न आदेश PID 5959 तक पाँच सेकंड तक प्रतीक्षा करता है:

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

इस उदाहरण में, यदि PID 5959 पांच सेकंड से पहले अपने स्वयं के समझौते से बाहर निकलता है, ${?}है 0। अगर पांच सेकंड के बाद नहीं ${?}लौटा 1

यह स्पष्ट रूप से ध्यान देने योग्य हो सकता है कि +r 1, 1चुनाव अंतराल (सेकंड में) है, इसलिए इसे स्थिति के अनुरूप बदला जा सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.