Nếu bất kỳ quá trình con sinh sản nào thất bại, giết tất cả và thoát


9

Trong tập lệnh của tôi, tôi chia ra một tập dữ liệu thành input_aa, input_ab, v.v. Sau đó, tôi chạy từng tập thông qua cùng một tập lệnh Python, như sau:

# Execute program on each split file
for part in input_*; do
        python3 $part &
done
wait

Câu hỏi của tôi là hai lần: làm thế nào để tôi phát hiện ra rằng một quá trình Python đã thất bại và khi được phát hiện, làm thế nào để tôi giết tất cả những đứa trẻ được sinh ra và thoát khỏi tập lệnh với một thất bại?

Câu trả lời:


10

Bạn có thể sử dụng một nhóm quy trình:

set -m
(
   for part in input_*; do
     (python3 "$part" || kill 0) &
   done
   wait
)

set -m(và tính năng vỏ POSIX tùy chọn, tính năng vỏ Unix bắt buộc) chạy các công việc trong nhóm quy trình riêng của họ. Trong bash, yash, zsh, mksh, đó là công việc của subshell nơi set -mđược kích hoạt vì thế bên ngoài (...)và tất cả các quá trình tạo ra trong đó sẽ được đặt trong nhóm quá trình tương tự.

Đối với dashvà các ashshell dựa khác , chỉ hoạt động ở quy trình shell cấp cao nhất. Vì vậy, mã đó sẽ hoạt động trừ khi nó được đặt trong một lớp con.

Điều đó sẽ không hoạt động trong AT & T kshhoặc vỏ SysV / Bourne cũ.

kill 0 gửi tín hiệu SIGTERM đến tất cả các thành viên của nhóm quy trình hiện tại.


Trong bash. Tại sao tôi bao gồm một shebang - vỏ yêu cầu không rõ ràng. Câu trả lời hay
jim mcnamara

@jimmcnamara, rằng công trình trong bash, dash, yash, mksh, zsh. Về cơ bản bất kỳ vỏ POSIX nhưng AT & T ksh. set -mlà (dưới-) được chỉ định trong POSIX nhưng là một tính năng tùy chọn.
Stéphane Chazelas

Tôi sử dụng Solaris. / bin / sh sẽ không bay.
jim mcnamara

@jimmcnamara, no / bin / sh trên Solaris 10 và trước đó là vỏ Bourne (không phải vỏ POSIX) và trên 11, AT & T ksh. Như tôi đã nói, nó hoạt động trong bash, dash, yash, mksh, zsh.
Stéphane Chazelas

1
@mikeerv, điều đó sẽ sửa lại quy trình thành 1, nhưng sẽ không đưa nó ra khỏi nhóm quy trình. kill 0Giết chết tất cả các thành viên của nhóm quy trình bất kể cha mẹ của họ là ai. Xem ps -jđể xem id nhóm quá trình.
Stéphane Chazelas

3

Đây là một ví dụ. CHƠI với điều này đầu tiên để có được chính xác những gì bạn cần. Nó không thể phá vỡ nhiều như vậy.

#!/bin/bash
# Example of killing off all children

> killfile
> outfile.err
kill_em()
{
   echo 'killing all children ' > 2
   while read pid
   do
      kill -0 $pid && kill -9 $pid  # if still running kill it
   done < killfile
   exit 1
}

export grandparentpid=$$
trap 'kill_em' 6
for i in 2 2 3 4 5 6 7 8 9 10
do
        ( sleep $i && ls oinkle  >> outfile 2>> outfile.err &
          pid=$!
          echo $pid >> killfile
          wait $!
          [ $? -ne 0 ] && kill -6 $grandparentpid
        ) &
done
wait

Đây là thiết lập để thất bại có chủ ý vì ls oinklesẽ thất bại (trên máy của tôi).

Khi bạn nhận được những gì bạn cần sau khi sửa lại tập lệnh khởi động --- Thay đổi:

for i in 2 2 3 4 5 6 7 8 9 10

đến:

for part in input_* 

thay đổi:

sleep $i && ls oinkle 

đến:

python3 $part 

Các chuyển hướng là có để lưu nhật ký. Bạn có thể không muốn chúng.


Đó là một chút không phù hợp. Nếu một trong những công việc thất bại trước khi tất cả các công việc khác đã bắt đầu, thì bạn killfilecó thể không chứa tất cả các công việc đã được bắt đầu.
Stéphane Chazelas

Một vài thực tiễn xấu như: biến không được trích dẫn, sử dụng số tín hiệu thay vì tên, sử dụng tín hiệu 6 (ví dụ ABRT trên Linux amd64) thay vì USR1 / USR2 làm tín hiệu người dùng, [ $? -ne 0 ]...
Stéphane Chazelas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.