दो पृष्ठभूमि आदेशों को देखते हुए, शेष एक को तब समाप्त करें जब या तो बाहर निकल जाए


14

मेरे पास एक साधारण बैश स्क्रिप्ट है जो दो सर्वर शुरू करती है:

#!/bin/bash
(cd ./frontend && gulp serve) & (cd ./backend && gulp serve --verbose)

यदि दूसरी कमांड बाहर निकलती है, तो ऐसा लगता है कि पहला कमांड चालू है।

मैं इसे कैसे बदल सकता हूं ताकि यदि या तो कमांड बाहर निकल जाए, तो दूसरा समाप्त हो जाए?

ध्यान दें कि हमें पृष्ठभूमि प्रक्रियाओं के त्रुटि स्तर की जांच करने की आवश्यकता नहीं है, बस वे बाहर निकल गए हैं या नहीं।


क्यों नहीं gulp ./fronend/serve && gulp ./backend/serve --verbose?
22

serveएक तर्क है, एक फ़ाइल नहीं है, इसलिए वर्तमान निर्देशिका को सेट करने की आवश्यकता है।
blah238

1
इसके अलावा ये लंबे समय से चल रही प्रक्रियाएं हैं जिन्हें समवर्ती रूप से चलाने की आवश्यकता है, अगर यह स्पष्ट नहीं था।
ब्लाह 238

जवाबों:


22

यह दोनों प्रक्रियाएं शुरू करता है, पहले खत्म होने का इंतजार करता है और फिर दूसरे को मारता है:

#!/bin/bash
{ cd ./frontend && gulp serve; } &
{ cd ./backend && gulp serve --verbose; } &
wait -n
pkill -P $$

यह काम किस प्रकार करता है

  1. शुरू:

    { cd ./frontend && gulp serve; } &
    { cd ./backend && gulp serve --verbose; } &
    

    उपरोक्त दोनों कमांड पृष्ठभूमि में दोनों प्रक्रियाओं को शुरू करते हैं।

  2. रुको

    wait -n

    यह या तो पृष्ठभूमि की नौकरी के समाप्त होने की प्रतीक्षा करता है।

    की वजह से -nविकल्प, इस बैश 4.3 या बेहतर की आवश्यकता है।

  3. को मार डालो

    pkill -P $$

    यह किसी भी नौकरी को मारता है जिसके लिए वर्तमान प्रक्रिया माता-पिता है। दूसरे शब्दों में, यह किसी भी पृष्ठभूमि प्रक्रिया को मारता है जो अभी भी चल रहा है।

    यदि आपके सिस्टम में नहीं है pkill, तो इस लाइन को बदलने का प्रयास करें:

    kill 0

    जो वर्तमान प्रक्रिया समूह को भी मारता है

आसानी से परीक्षण योग्य उदाहरण

स्क्रिप्ट को बदलकर, हम इसे gulpस्थापित किए बिना भी परीक्षण कर सकते हैं :

$ cat script.sh 
#!/bin/bash
{ sleep $1; echo one;  } &
{ sleep $2; echo two;  } &
wait -n
pkill -P $$
echo done

उपरोक्त स्क्रिप्ट के रूप में चलाया जा सकता है bash script.sh 1 3और पहली प्रक्रिया पहले समाप्त हो जाती है। वैकल्पिक रूप से, एक इसे चला सकता है bash script.sh 3 1और दूसरी प्रक्रिया पहले समाप्त होगी। किसी भी मामले में, कोई भी यह देख सकता है कि यह वांछित के रूप में संचालित होता है।


यह बहुत अच्छा लग रहा है। दुर्भाग्य से वे आदेश मेरे bash पर्यावरण (msysgit) पर काम नहीं करते हैं। यह निर्दिष्ट नहीं करने के लिए मेरा बुरा है। यद्यपि मैं एक वास्तविक लिनक्स बॉक्स पर इसे आज़माऊंगा।
blah238

(1) कमांड bashके -nविकल्प के समर्थन के सभी संस्करण नहीं wait। (२) मैं पहले वाक्य से १००% सहमत हूँ - आपका समाधान दो प्रक्रियाओं को शुरू करता है, पहले एक को समाप्त करने की प्रतीक्षा करता है और फिर दूसरे को मारता है। लेकिन सवाल यह है कि "... यदि या तो कमांड की त्रुटियां हैं , तो दूसरा समाप्त हो गया है?" मुझे विश्वास है कि आपका समाधान वह नहीं है जो ओपी चाहता है। (३) आप क्यों बदल (…) &गए { …; } &? &बलों सूची (समूह आदेश) वैसे भी एक subshell में चलाने के लिए। IMHO, आपने वर्ण जोड़े हैं और संभवतः भ्रम की स्थिति पैदा की है (मुझे इसे समझने के लिए दो बार इसे देखना पड़ा) बिना किसी लाभ के।
जी-मैन का कहना है कि 'मोनिका' की बहाली

1
जॉन सही है, वे वेब सर्वर हैं जो आम तौर पर दोनों को चलते रहना चाहिए जब तक कि कोई त्रुटि नहीं होती है या उन्हें समाप्त करने के लिए संकेत दिया जाता है। इसलिए मुझे नहीं लगता कि हमें प्रत्येक प्रक्रिया के त्रुटि स्तर की जांच करने की आवश्यकता है, बस यह अभी भी चल रहा है।
blah238

2
pkillमेरे लिए उपलब्ध नहीं है लेकिन kill 0लगता है कि समान प्रभाव है। इसके अलावा मैंने Windows वातावरण के लिए अपना Git अपडेट किया और यह wait -nअब काम करता है, इसलिए मैं इस उत्तर को स्वीकार कर रहा हूं।
blah238

1
दिलचस्प। हालाँकि मैं देख रहा हूँ कि यह व्यवहार कुछ संस्करणों के लिए प्रलेखित है kill। मेरे सिस्टम पर प्रलेखन इसका उल्लेख नहीं करता है। हालाँकि, kill 0वैसे भी काम करता है। अच्छा खोजो!
जॉन 1024

1

यह मुश्किल है। यहाँ मैं क्या तैयार है; इसे सरल / सरल बनाना संभव हो सकता है:

#!/bin/sh

pid1file=$(mktemp)
pid2file=$(mktemp)
stat1file=$(mktemp)
stat2file=$(mktemp)

while true; do sleep 42; done &
main_sleeper=$!

(cd frontend && gulp serve           & echo "$!" > "$pid1file";
    wait "$!" 2> /dev/null; echo "$?" > "$stat1file"; kill "$main_sleeper" 2> /dev/null) &
(cd backend  && gulp serve --verbose & echo "$!" > "$pid2file";
    wait "$!" 2> /dev/null; echo "$?" > "$stat2file"; kill "$main_sleeper" 2> /dev/null) &
sleep 1
wait "$main_sleeper" 2> /dev/null

if stat1=$(<"$stat1file")  &&  [ "$stat1" != "" ]  &&  [ "$stat1" != 0 ]
then
        echo "First process failed ..."
        if pid2=$(<"$pid2file")  &&  [ "$pid2" != "" ]
        then
                echo "... killing second process."
                kill "$pid2" 2> /dev/null
        fi
fi
if [ "$stat1" = "" ]  &&  \
   stat2=$(<"$stat2file")  &&  [ "$stat2" != "" ]  &&  [ "$stat2" != 0 ]
then
        echo "Second process failed ..."
        if pid1=$(<"$pid1file")  &&  [ "$pid1" != "" ]
        then
                echo "... killing first process."
                kill "$pid1" 2> /dev/null
        fi
fi

wait
if stat1=$(<"$stat1file")
then
        echo "Process 1 terminated with status $stat1."
else
        echo "Problem getting status of process 1."
fi
if stat2=$(<"$stat2file")
then
        echo "Process 2 terminated with status $stat2."
else
        echo "Problem getting status of process 2."
fi
  • सबसे पहले, एक प्रक्रिया ( while true; do sleep 42; done &) शुरू करें जो हमेशा के लिए सोती / रुकती है। यदि आप सुनिश्चित हैं कि आपकी दो आज्ञाएँ एक निश्चित समय (जैसे, एक घंटे) के भीतर समाप्त हो जाएंगी, तो आप इसे एक ही नींद में बदल सकते हैं जो कि (जैसे, sleep 3600) से अधिक हो जाएगी । आप इसे समय-सीमा के रूप में उपयोग करने के लिए निम्न तर्क बदल सकते हैं; यदि वे उस समय के बाद भी चल रहे हैं, तो प्रक्रियाओं को मारें। (ध्यान दें कि उपरोक्त स्क्रिप्ट वर्तमान में ऐसा नहीं करती है।)
  • दो अतुल्यकालिक (समवर्ती पृष्ठभूमि) प्रक्रियाओं को शुरू करें।
    • आप की जरूरत नहीं है ./के लिए cd
    • command & echo "$!" > somewhere; wait "$!" एक मुश्किल निर्माण है जो अतुल्यकालिक रूप से एक प्रक्रिया शुरू करता है, अपने पीआईडी ​​को पकड़ता है, और फिर इसका इंतजार करता है; इसे एक अग्रभूमि (सिंक्रोनस) प्रक्रिया की तरह बनाया जा रहा है। लेकिन यह एक (…)सूची के भीतर होता है, जो पूरी तरह से पृष्ठभूमि में है, इसलिए gulpप्रक्रियाएं अतुल्यकालिक रूप से चलती हैं।
    • या तो gulpप्रक्रियाओं से बाहर निकलने के बाद, एक अस्थायी फ़ाइल में अपनी स्थिति लिखें और "हमेशा की नींद" प्रक्रिया को मार दें।
  • sleep 1 एक दौड़ की स्थिति से बचाने के लिए जहां पहली पृष्ठभूमि प्रक्रिया दूसरे से पहले मर जाती है उसे फ़ाइल पर अपना पीआईडी ​​लिखने का मौका मिलता है।
  • समाप्त करने के लिए "हमेशा की नींद" प्रक्रिया की प्रतीक्षा करें। इस के बाद क्या होता है या तो के gulpरूप में ऊपर कहा गया है, प्रक्रियाओं बाहर निकलता है।
  • देखें कि किस पृष्ठभूमि की प्रक्रिया समाप्त हुई। यदि यह विफल रहा, तो दूसरे को मार डालो।
  • यदि एक प्रक्रिया विफल हो गई और हमने दूसरे को मार दिया, तो दूसरे को लपेटने और उसकी स्थिति को फ़ाइल में सहेजने के लिए प्रतीक्षा करें। यदि पहली प्रक्रिया सफलतापूर्वक समाप्त हो गई है, तो दूसरे के समाप्त होने की प्रतीक्षा करें।
  • दो प्रक्रियाओं की स्थिति की जाँच करें।

1

पूर्णता के लिए यहां मैंने वह प्रयोग किया है जो निम्नलिखित है:

#!/bin/bash
(cd frontend && gulp serve) &
(cd backend && gulp serve --verbose) &
wait -n
kill 0

यह मेरे लिए विंडोज 2.5.3 64-बिट के लिए गिट पर काम करता है। पुराने संस्करण -nविकल्प को स्वीकार नहीं कर सकते हैं wait


1

मेरे सिस्टम (Centos) पर, मेरे waitपास -nऐसा नहीं था:

{ sleep 3; echo one;  } &
FOO=$!
{ sleep 6; echo two;  } &
wait $FOO
pkill -P $$

यह "या तो" की प्रतीक्षा नहीं करता है, बल्कि पहले वाले का इंतजार करता है। लेकिन फिर भी यह मदद कर सकता है यदि आप जानते हैं कि कौन सा सर्वर पहले बंद हो जाएगा।


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