2013-08-16 12 views
9

Ben arka plan işlemleri olarak sonsuz komutları çalışan bir bash:bash kapatma kancası; Ana süreç öldürülünce veya tüm arka plan işlemlerini kapatma

#!/bin/bash 

function xyz() { 
    # some awk command 
} 

endlesscommand "param 1" | xyz & # async 
pids=$! 
endlesscommand "param 2" | xyz & # async 
pids="$pids "$! 
endlesscommand "param 3" | xyz # sync so the script doesn't leave 

bu senaryoyu durdurmanın tek yoludur (olmalıdır) Ctrl-C veya öldürmek ve Bu olduğunda, $ pids değişkeninde listelenen tüm arka plan süreçlerini öldürmem gerekiyor. Bunu nasıl yaparım?

o, ben böyle bir şey yapsın anacı üzerine öldürmek sinyalini yakalamak ve bu olduğunda (kapatma kanca) bir işlevi yürütmek mümkün olsaydı:

for $pid in $pids; do kill $pid; done; 

Ama bulamıyorum nasıl bunu yapmak ...


ÇÖZÜM aşağıdaki yayınlardan:

#!/bin/bash 

function xyz() { 
# some awk command 
} 

trap 'jobs -p | xargs kill' EXIT # part of the solution 

endlesscommand "param 1" | xyz & # async 
endlesscommand "param 2" | xyz & # async 
endlesscommand "param 3" | xyz & # don't sync, but wait: 

# other part of the solution: 
while pgrep -P "$BASHPID" > /dev/null; do 
    wait 
done 
+0

Tuzakları kullanmanız gerekir ... – devnull

+0

Çocuk süreçlerinin açık bir listesini tutmaya gerek yok; Çalışmakta olan çocukların işlem kimliklerini almak için 'iş -p' diyebilirsiniz. – chepner

cevap

10

Eğer pids izlemek gerekmez bir tuzak etkileyen "endlesscommand" olduğu ebeveyn işlemleri için bakacağız

:

trap 'jobs -p | xargs kill' EXIT 

DÜZENLEME: @Barmar sordu Bu, iş kontrolünün genellikle mevcut olmadığı, kaynaklı olmayan komut dosyaları içinde çalışır. Öyle. üç grup liderlerinin pids bkz çalıştırdığınızda

$ cat no-job-control 
#! /bin/bash 

set -e -o pipefail 

# Prove job control is off 
if suspend 
then 
    echo suspended 
else 
    echo suspension failed, job control must be off 
fi 

echo 

# Set up the trap 
trap 'jobs -p | xargs kill' EXIT 

# Make some work 
(echo '=> Starting 0'; sleep 5; echo '=> Finishing 0') & 
(echo '=> Starting 1'; sleep 5; echo '=> Finishing 1') & 
(echo '=> Starting 2'; sleep 5; echo '=> Finishing 2') & 

echo "What's in jobs -p?" 
echo 

jobs -p 

echo 
echo "Ok, exiting now" 
echo 

ve sonra onları öldürülmesini: Bu komut dosyasını düşünün

$ ./no-job-control 
./no-job-control: line 6: suspend: cannot suspend: no job control 
suspension failed, job control must be off 

=> Starting 0 
What's in jobs -p? 
=> Starting 1 

54098 
54099 
54100 

Ok, exiting now 

=> Starting 2 
./no-job-control: line 31: 54098 Terminated: 15   (echo '=> Starting 0'; sleep 5; echo '=> Finishing 0') 
./no-job-control: line 31: 54099 Terminated: 15   (echo '=> Starting 1'; sleep 5; echo '=> Finishing 1') 
./no-job-control: line 31: 54100 Terminated: 15   (echo '=> Starting 2'; sleep 5; echo '=> Finishing 2') 

yerine trap hattı ve yeniden çalıştırması yorum yaparsanız, Üç iş ölmez ve aslında son mesajlarını birkaç saniye sonra basar. Son çıktılarla ara verilen iade istemi dikkat edin.

$ ./no-job-control 
./no-job-control: line 6: suspend: cannot suspend: no job control 
suspension failed, job control must be off 

=> Starting 0 
What's in jobs -p? 

54110 
54111 
54112 
=> Starting 1 

Ok, exiting now 

=> Starting 2 
$ => Finishing 0 
=> Finishing 2 
=> Finishing 1 
+1

Teşekkürler, borularla bile harika çalışıyor! :) ve daha da kısa olabilir: trap 'jobs -p | xargs kill 'EXIT – fabien

+0

' İşler -p ', iş kontrolü etkin olmasa bile, komut dosyaları içinde gerçekten çalışır mı? – Barmar

+0

@Barmar Düzenlemeleri görün. – phs

0
kill `ps axl | grep "endlesscommand" | awk '{printf $4" "}'` 
Bu İşte
+0

'kill -9' hafifçe kullanılmamalıdır. Basit bir 'öldürme' yeterli olmalıdır. Ayrıca, bu öldürür * sadece * öldürülür ebeveyn tarafından başlatılan değil, 'sonsuzluk 'çalışan tüm * süreçleri. – chepner

+0

@chepner Yumurtlanmış süreçler için doğru değil ... OP tüm süreçleri öldürmek istiyor, bu yüzden neden öldürmeyi -9’un güvensiz olduğunu anlamıyorum? – iamauser

+0

'kill -9' öldürülen işlemi kendiliğinden temizlemek için herhangi bir şans vermez: yakın dosyalar, floş tamponları, vb – chepner

1

Böyle anacı altında oluşturulan tüm işlemleri öldürmek için pgrep ve bir fonksiyonun yararlanabilirler. Bu sadece doğrudan çocuk süreçlerini değil, aynı zamanda onun altında yaratılanları da öldürür.

#!/bin/bash 

function killchildren { 
    local LIST=() IFS=$'\n' A 
    read -a LIST -d '' < <(exec pgrep -P "$1") 
    local A SIGNAL="${2:-SIGTERM}" 
    for A in "${LIST[@]}"; do 
     killchildren_ "$A" "$SIGNAL" 
    done 
} 

function killchildren_ { 
    local LIST=() 
    read -a LIST -d '' < <(exec pgrep -P "$1") 
    kill -s "$2" "$1" 
    if [[ ${#LIST[@]} -gt 0 ]]; then 
     local A 
     for A in "${LIST[@]}"; do 
      killchildren_ "$A" "$2" 
     done 
    fi 
} 

trap 'killchildren "$BASHPID"' EXIT 

endlesscommand "param 1" & 
endlesscommand "param 2" & 
endlesscommand "param 3" & 

while pgrep -P "$BASHPID" >/dev/null; do 
    wait 
done 

orijinal kod gelince, o sadece diziler kullanmak daha iyi olurdu ve ayrıca döngü için kullanmaya gerek yoktur:

#!/bin/bash 

trap 'kill "${pids[@]}"' EXIT 

pids=() 
endlesscommand "param 1" & # async 
pids+=("$!") 
endlesscommand "param 2" & # async 
pids+=("$!") 
endlesscommand "param 3" & # syncing this is not a good idea since if the main process would end along with it if it ends earlier. 
pids+=("$!") 

while pgrep -P "$BASHPID" >/dev/null; do 
    wait 
done 

Orijinal fonksiyon referansı: http://www.linuxquestions.org/questions/blog/konsolebox-210384/bash-functions-to-list-and-kill-or-send-signals-to-process-trees-34624/

+0

Bu son çözümü denedim ve işe yarıyor ... ama benim sonsuza dek başka bir program/işlevle (sorularımı güncelledim) pipetlemedim. Sonunda, pgrep loop & phs çözümünü kullanıyorum ve çok iyi çalışıyor. :) – fabien