İki arka plan komutu verildiğinde, her iki çıkıştan da geri kalanı sonlandırın


14

İki sunucu başlatan basit bir bash komut dosyası var:

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

İkinci komut çıkarsa, ilk komut çalışmaya devam eder.

Komutlardan biri çıkarsa diğeri sonlandırılacak şekilde bunu nasıl değiştirebilirim?

Arka plan işlemlerinin hata düzeylerini, yalnızca çıkıp çıkmadıklarını kontrol etmemiz gerekmediğini unutmayın.


Neden olmasın gulp ./fronend/serve && gulp ./backend/serve --verbose?
heemayl

servebir argümandır, bir dosya değildir, dolayısıyla geçerli dizinin ayarlanması gerekir.
blah238

1
Ayrıca bunlar eşzamanlı olarak çalışması gereken uzun süren süreçlerdir, eğer net değilse, üzgünüm.
blah238

Yanıtlar:


22

Bu her iki işlemi de başlatır, ilkini bitirir ve sonra diğerini öldürür:

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

Nasıl çalışır

  1. Başlat:

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

    Yukarıdaki iki komut her iki işlemi de arka planda başlatır.

  2. Bekle

    wait -n

    Bu, her iki arka plan işinin de sona ermesini bekler.

    -nSeçenek nedeniyle , bu bash 4.3 veya daha iyisini gerektirir.

  3. Öldürmek

    pkill -P $$

    Bu, geçerli işlemin üst olduğu herhangi bir işi öldürür. Başka bir deyişle, bu hala devam eden arka plan işlemlerini öldürür.

    Sisteminizde yoksa pkill, bu satırı değiştirmeyi deneyin:

    kill 0

    bu da mevcut süreç grubunu öldürüyor .

Kolayca test edilebilir örnek

Betiği değiştirerek, yüklemeden bile test edebiliriz gulp:

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

Yukarıdaki komut dosyası şu şekilde çalıştırılabilir bash script.sh 1 3ve ilk işlem önce sona erer. Alternatif olarak, kişi şu şekilde çalıştırılabilir bash script.sh 3 1ve ikinci işlem önce sona erer. Her iki durumda da, bunun istendiği gibi çalıştığını görebilirsiniz.


Harika görünüyor. Ne yazık ki bu komutlar bash ortamımda (msysgit) çalışmıyor. Bunu belirtmemek benim için kötü. Gerçi gerçek bir Linux kutusunda deneyeceğim.
blah238

(1) Tüm sürümler komut seçeneğini bashdesteklemez . (2) İlk cümle ile% 100 katılıyorum - çözümünüz iki işlem başlatıyor, ilk işlemin bitmesini bekliyor ve sonra diğerini öldürüyor. Ama soru “… her iki komutta hata varsa , diğeri sonlandırılır mı?” Diyor. Çözümünüzün OP'nin istediği şey olmadığına inanıyorum. (3) Neden değiştirdin için ? Yine de listeyi (grup komutu) alt kabukta çalışmaya zorlar. IMHO, karakterler eklediniz ve muhtemelen karışıklık getirdiniz (anlamak için iki kez bakmam gerekiyordu). -nwait(…) &{ …; } &&
G-Man, 'Monica'yı Yeniden Başlat' diyor

1
John doğrudur, bir hata oluşmadıkça veya sonlandıkları bildirilmedikçe normal olarak her ikisinin de çalışmaya devam etmesi gereken web sunuculardır. Bu yüzden her işlemin hata seviyesini kontrol etmemiz gerektiğini düşünmüyorum, sadece hala çalışıyor mu.
blah238

2
pkillbenim için mevcut değil ama kill 0aynı etkiye sahip gibi görünüyor. Ayrıca Windows için Git ortamımı güncelledim ve wait -nşimdi çalışıyor gibi görünüyor , bu yüzden bu yanıtı kabul ediyorum.
blah238

1
İlginç. O davranış için belgelenmiştir görüyoruz rağmen bazı sürümlerinde arasında kill. sistemimdeki belgeler bundan bahsetmiyor. Ancak, kill 0yine de çalışır. İyi bulmak!
John1024

1

Bu zor. İşte benim geliştirdiğim; basitleştirmek / kolaylaştırmak mümkün olabilir:

#!/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
  • İlk olarak, while true; do sleep 42; done &sonsuza kadar uyuyan / duraklatan bir işlem ( ) başlatın . İki komutunuzun belirli bir süre içinde sona ereceğinden eminseniz (örn. Bir saat), bunu bunu aşacak tek bir uyku olarak değiştirebilirsiniz (örn sleep 3600.). Daha sonra bunu bir zaman aşımı olarak kullanmak için aşağıdaki mantığı değiştirebilirsiniz; yani, eğer bu süreden sonra hala çalışıyorlarsa süreçleri öldürün. (Yukarıdaki komut dosyasının şu anda bunu yapmadığını unutmayın.)
  • İki eşzamansız (eşzamanlı arka plan) işlemi başlatın.
    • Buna gerek yok ./için cd.
    • command & echo "$!" > somewhere; wait "$!" bir süreci eşzamansız olarak başlatan, PID'sini yakalayan ve daha sonra onu bekleyen zor bir yapıdır; ön plan (eşzamanlı) bir süreç haline getirir. Ancak bu (…), tamamen arka planda bulunan bir liste içinde gerçekleşir , bu nedenle gulpişlemler eşzamansız olarak çalışır.
    • gulpİşlemlerden herhangi biri çıktıktan sonra durumunu geçici bir dosyaya yazın ve “sonsuza kadar uyku” işlemini öldürün.
  • sleep 1 ilk arka plan işleminin ikincisinden önce öldüğü bir yarış durumuna karşı koruma sağlamak için PID'sini dosyaya yazma şansı elde edilir.
  • “Sonsuza kadar uyku” sürecinin sona ermesini bekleyin. Bu , yukarıda belirtildiği gibi işlemlerden herhangi birinden sonra gerçekleşir gulp.
  • Hangi arka plan işleminin sonlandığını görün. Başarısız olursa, diğerini öldür.
  • Bir işlem başarısız olursa ve diğerini öldürürsek, ikincisinin tamamlanmasını bekleyin ve durumunu bir dosyaya kaydedin. İlk işlem başarıyla tamamlandıysa, ikincisinin bitmesini bekleyin.
  • İki işlemin durumlarını kontrol edin.

1

Tamlık için burada kullanarak sona erdi:

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

Bu benim için Git for Windows 2.5.3 64-bit üzerinde çalışıyor. Eski sürümler -nseçeneği kabul etmeyebilir wait.


1

Sistemimde (Centos) günü waityok -nben bunu böylece:

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

Bu "ikisini de" beklemez, ilkini bekler. Ama yine de ilk olarak hangi sunucunun durdurulacağını biliyorsanız yardımcı olabilir.


İster waitsahiptir -nseçeneği ya da değil kullandığınız kabuk değil, Linux dağıtımı bağlıdır.
Kusalananda
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.