Jika ada proses melahirkan anak gagal, bunuh semua dan keluar

9

Dalam skrip saya, saya membagi set data menjadi input_aa, input_ab, dll. Kemudian, saya menjalankan masing-masing melalui skrip Python yang sama, seperti:

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

Pertanyaan saya ada dua: bagaimana saya mendeteksi bahwa proses Python telah gagal, dan ketika terdeteksi, bagaimana saya membunuh semua anak yang dilahirkan dan keluar dari skrip dengan gagal?

Menimpa
sumber

Jawaban:

10

Anda dapat menggunakan grup proses:

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

set -m(dan fitur shell POSIX opsional, diperlukan fitur shell Unix) menjalankan pekerjaan dalam grup proses mereka sendiri. Dalam bash, yash, zsh, mksh, itulah pekerjaan dari subkulit mana set -mdiaktifkan sehingga luar (...)dan semua proses dibuat dalam yang akan ditempatkan dalam kelompok proses yang sama.

Untuk dashdan ashshell berbasis lainnya , yang hanya bekerja pada proses shell level atas. Jadi kode itu akan berfungsi kecuali dimasukkan dalam subkulit.

Itu tidak akan bekerja di AT&T kshatau shell SysV / Bourne sama sekali.

kill 0 mengirimkan sinyal SIGTERM ke semua anggota grup proses saat ini.

Stéphane Chazelas
sumber
Di bash. Mengapa saya memasukkan shebang - shell yang dibutuhkan tidak jelas. Jawaban yang bagus
jim mcnamara
@jimmcnamara, yang bekerja dalam bash, dash, yash, mksh, zsh. Pada dasarnya setiap shell POSIX kecuali AT&T ksh. set -mditentukan (kurang-) dalam POSIX tetapi sebagai fitur opsional.
Stéphane Chazelas
Saya menggunakan Solaris. / bin / sh tidak akan terbang.
jim mcnamara
@jimmcnamara, no / bin / sh pada Solaris 10 dan sebelumnya adalah shell Bourne (bukan shell POSIX), dan pada 11, AT&T ksh. Seperti yang saya katakan, ini berfungsi dalam bash, dash, yash, mksh, zsh.
Stéphane Chazelas
1
@ mikeserv, itu akan membuat proses reparent ke 1, tetapi tidak akan mengeluarkannya dari grup proses. kill 0membunuh semua anggota grup proses apa pun orang tua mereka. Lihat ps -juntuk melihat id grup proses.
Stéphane Chazelas
3

Ini sebuah contoh. MAINKAN ini dulu untuk mendapatkan apa yang Anda butuhkan. Tidak bisa pecah seperti sekarang.

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

Ini sengaja diatur untuk gagal karena ls oinkleakan gagal (di mesin saya).

Ketika Anda mendapatkan apa yang Anda butuhkan setelah bermain-main dengan skrip starter --- Ubah:

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

untuk:

for part in input_* 

perubahan:

sleep $i && ls oinkle 

untuk:

python3 $part 

Pengalihan ada untuk menyimpan log. Anda mungkin tidak menginginkannya.

jim mcnamara
sumber
Agak bersemangat. Jika salah satu pekerjaan gagal sebelum semua yang lain dimulai, maka Anda killfilemungkin tidak mengandung semua tawaran pekerjaan yang telah dimulai.
Stéphane Chazelas
Beberapa praktik buruk seperti: variabel tanda kutip, penggunaan nomor sinyal alih-alih nama, gunakan sinyal 6 (misalnya, ABRT di Linux amd64) alih-alih USR1 / USR2 sebagai sinyal pengguna, [ $? -ne 0 ]...
Stéphane Chazelas