2013-08-16 57 views
9

Tôi có một bash chạy lệnh vô tận như quá trình nền:móc bash tắt máy; hoặc, giết tất cả các quá trình nền khi quá trình chính là giết

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

Cách duy nhất để ngăn chặn kịch bản này là (phải) Ctrl-C hoặc giết và khi điều đó xảy ra, tôi cần phải giết tất cả các quy trình nền được liệt kê trong biến $ pids. Tôi làm như thế nào?

Nếu nó đã có thể nắm bắt những tín hiệu kill về quá trình chính và thực hiện một chức năng khi điều đó xảy ra (tắt máy móc), tôi sẽ làm một cái gì đó như:

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

Nhưng tôi không thể tìm thấy làm thế nào để làm điều này ...


SOLUTION từ bài viết sau đây:

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

Bạn cần phải sử dụng bẫy ... – devnull

+0

Không cần phải duy trì một danh sách rõ ràng về các quá trình con; bạn có thể gọi 'jobs -p' để lấy các ID quá trình của các trẻ em vẫn đang chạy. – chepner

Trả lời

10

Dưới đây là một cái bẫy mà không cần bạn để theo dõi pids:

trap 'jobs -p | xargs kill' EXIT 

EDIT: @Barmar hỏi nếu điều này hoạt động trong các tập lệnh không có nguồn gốc, nơi kiểm soát công việc thường không khả dụng. Nó có. Hãy xem xét kịch bản này:

$ 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 

Khi chạy chúng ta thấy PID của ba nhà lãnh đạo nhóm, và sau đó nhìn thấy chúng giết:

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

Nếu chúng ta thay vì nhận xét ra các trap dòng và tái chạy, ba công việc không chết và trong thực tế in ra thông điệp cuối cùng của họ một vài giây sau đó. Chú ý dấu nhắc trả về xen kẽ với các đầu ra cuối cùng.

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

Cảm ơn, hoạt động tuyệt vời, ngay cả với đường ống! :) và thậm chí có thể ngắn hơn: bẫy 'jobs -p | xargs kill 'EXIT – fabien

+0

Có phải 'jobs -p' thực sự làm việc bên trong các script, mặc dù chúng không được kích hoạt việc kiểm soát? – Barmar

+0

@Barmar Xem chỉnh sửa. – phs

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

này sẽ tìm kiếm các quá trình cha mẹ đang ảnh hưởng đến "endlesscommand"

+0

'kill -9' không được sử dụng một cách nhẹ nhàng. Một 'kill' đơn giản là đủ. Ngoài ra, điều này giết chết tất cả * các tiến trình đang chạy 'endlesscommand', không chỉ những tiến trình do cha mẹ bắt đầu bị giết. – chepner

+0

@chepner Không chính xác cho quá trình sinh sản ... OP muốn giết tất cả các quy trình liên quan, vì vậy tôi không hiểu tại sao 'kill -9' là không an toàn? – iamauser

+0

'kill -9' không cung cấp cho quá trình giết chết bất kỳ cơ hội để làm sạch sau khi chính nó: đóng tập tin, bộ đệm tuôn ra, vv – chepner

1

Bạn có thể sử dụng pgrep và chức năng để tiêu diệt tất cả các quy trình được tạo trong quá trình chính như thế này. Điều này sẽ không chỉ giết chết các tiến trình con trực tiếp mà còn là những tiến trình được tạo ra bên dưới nó.

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

Đối với mã ban đầu của bạn, nó sẽ là tốt hơn để chỉ cần sử dụng mảng, và bạn cũng không cần phải sử dụng một vòng lặp 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 

tham khảo chức năng Original: http://www.linuxquestions.org/questions/blog/konsolebox-210384/bash-functions-to-list-and-kill-or-send-signals-to-process-trees-34624/

+0

Tôi đã cố gắng giải pháp cuối cùng này và nó hoạt động ... nhưng không phải nếu vô tận của tôi là đường ống với một số chương trình/chức năng khác (tôi cập nhật câu hỏi của tôi). Cuối cùng, tôi đang sử dụng giải pháp pgrep loop & phs của bạn và nó hoạt động rất tốt. :) – fabien