Se i processi figlio generati falliscono, uccidi tutti ed esci


9

Nel mio script ho diviso un set di dati in input_aa, input_ab, ecc. Quindi, eseguo ciascuno attraverso lo stesso script Python, come tale:

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

La mia domanda è duplice: come posso rilevare che un processo Python è fallito e, quando rilevato, come posso uccidere tutti i bambini generati e uscire dallo script con un errore?

Risposte:


10

È possibile utilizzare un gruppo di processi:

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

set -m(e la funzione shell POSIX opzionale, funzione shell Unix richiesta) esegue i lavori nel proprio gruppo di processi. In bash, yash, zsh, mksh, che è lavori del sottoshell cui set -mè abilitato per consentire l'esterno (...)e tutti i processi creati all'interno che verranno messi in quello stesso gruppo processo.

Per dashe altre ashshell basate, funziona solo con il processo di shell di livello superiore. Quindi quel codice funzionerà a meno che non sia inserito in una subshell.

Ciò non funzionerà affatto in AT&T ksho nella vecchia shell SysV / Bourne.

kill 0 invia un segnale SIGTERM a tutti i membri del gruppo di processi corrente.


In bash. Perché ho incluso uno shebang: la shell richiesta non è chiara. Buona risposta
jim mcnamara

@jimmcnamara, che lavori in bash, dash, yash, mksh, zsh. Praticamente qualsiasi shell POSIX ma AT&T ksh. set -mè (sotto-) specificato in POSIX ma come funzionalità opzionale.
Stéphane Chazelas,

Uso Solaris. / bin / sh non volerà.
jim mcnamara,

@jimmcnamara, no / bin / sh su Solaris 10 e precedenti è la shell Bourne (non una shell POSIX), e su 11, AT&T ksh. Come ho detto, funziona in bash, dash, yash, mksh, zsh.
Stéphane Chazelas,

1
@mikeserv, che riporterebbe il processo a 1, ma non lo eliminerebbe dal gruppo di processi. kill 0uccide tutti i membri del gruppo di processo qualunque sia il loro genitore. Vedere ps -jper vedere gli ID dei gruppi di processi.
Stéphane Chazelas,

3

Questo è un esempio GIOCA con questo per primo per ottenere esattamente quello che ti serve. Non può rompersi molto come è.

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

Questa installazione fallisce deliberatamente perché ls oinklefallirà (sulla mia macchina).

Quando ottieni ciò di cui hai bisogno dopo aver armeggiato con lo script iniziale --- Modifica:

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

per:

for part in input_* 

modificare:

sleep $i && ls oinkle 

per:

python3 $part 

I reindirizzamenti sono lì per salvare i registri. Potresti non volerli.


È un po 'audace. Se uno dei lavori fallisce prima che tutti gli altri siano stati avviati, è killfilepossibile che non si contengano tutti i pid dei lavori che sono stati avviati.
Stéphane Chazelas,

Alcune cattive pratiche come: variabili non quotate, uso di numeri di segnale anziché nomi, uso del segnale 6 (ABRT su Linux amd64 per esempio) invece di USR1 / USR2 come segnale utente, [ $? -ne 0 ]...
Stéphane Chazelas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.