2013-08-16 95 views
9

我有一個運行無盡的命令作爲後臺進程是bash:bash關機掛鉤;或者,殺死所有後臺進程,當主進程被殺死

#!/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 

停止該腳本的唯一方法是(必須)按Ctrl-C或殺滅和當發生這種情況時,我需要殺死$ pids變量中列出的所有後臺進程。 我該怎麼做?

如果有可能趕在主過程中的終止信號,這時執行功能(關閉掛鉤),我會做這樣的事情:

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

但我找不到如何從以下職位做到這一點...


SOLUTION

#!/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

你需要使用陷阱... – devnull

+0

沒有必要維護一個明確的子進程列表;您可以調用'jobs -p'來獲取仍在運行的子進程的ID。 – chepner

回答

10

下面是一個不需要你跟蹤pids陷阱的父進程:

trap 'jobs -p | xargs kill' EXIT 

編輯:@Barmar問這可以在通常不可用的作業控制非源腳本內工作。它的確如此。考慮一下這個腳本:

$ 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 

在運行的時候,我們看到三個組長的PID,然後看到他們殺:

$ ./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') 

如果我們不是註釋掉trap線並重新運行時,三個工作不會消失,實際上幾秒鐘後就會打印出他們的最終消息。注意返回的提示與最終輸出交錯。

$ ./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

謝謝,即使有管道也很好! :) 它甚至可以更短: trap'jobs -p | xargs kill'EXIT – fabien

+0

'作業-p'是否真的可以在腳本中使用,即使它們沒有啓用作業控制? – Barmar

+0

@Barmar請參閱編輯。 – phs

0
kill `ps axl | grep "endlesscommand" | awk '{printf $4" "}'` 

這將尋找那些被影響「endlesscommand」

+0

'kill -9'不能輕易使用。一個簡單的'殺死'應該就足夠了。此外,這會殺死運行'endlesscommand'的所有進程,而不僅僅是那些正在被殺死的父進程啓動的進程。 – chepner

+0

@chepner對於衍生進程不正確...... OP想要殺死所有涉及的進程,所以我不明白爲什麼'kill -9'不安全? – iamauser

+0

'kill -9'不會讓被殺死的進程有任何機會清理自己:關閉文件,刷新緩衝區等。 – chepner

1

你可以使用pgrep和一個函數來殺死在主進程下創建的所有進程,像這樣。這不僅會殺死直接的子進程,而且還會殺死直接子進程。

#!/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 

至於你的原代碼,這將是最好只使用數組,你也不需要使用一個for循環:

#!/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 

原函數參考:http://www.linuxquestions.org/questions/blog/konsolebox-210384/bash-functions-to-list-and-kill-or-send-signals-to-process-trees-34624/

+0

我試過這最後的解決方案,它的工作原理...但如果我的無盡命令是與一些其他程序/功能管道(我更新了我的問題)不是。 最後,我使用你的pgrep loop&phs解決方案,它工作得很好。 :) – fabien