2015-08-27 4 views
5

Ho visto la seguente domanda: Bash run two commands and get output from both che quasi risponde al mio bisogno.Eseguire più comandi in parallelo e restituire ogni volta che uno di essi ha esito negativo o tutti hanno esito positivo

Tuttavia, il comando wait sta bloccando, quindi ciò significa che se il comando 2 fallisce prima che il comando 1 abbia esito positivo, il comando non ritornerà quando il comando 2 non riesce ma solo quando il comando 1 ha esito positivo.

È possibile eseguire più comandi in parallelo e restituire 1 ogni volta che uno di essi non riesce e restituire 0 se tutti hanno esito positivo (e tornare al più presto possibile)?

Sarebbe ancora meglio se ciò fosse possibile utilizzando i comandi standard (come xargs o parallelo), ma anche ok se è stato scritto usando bash.

+0

Se uno dei comandi non riesce, si desidera uccidere l'altro prima di restituire o mantenere in esecuzione l'altro? – Alepac

+0

Sì, sarebbe meglio (uccidere l'altro comando) – edi9999

+0

Hai guardato [questo thread] (http://stackoverflow.com/questions/9145528/barrier-in-bash-can-it-be-done-easily)? Simula il comportamento di un barier in bash – Aserre

risposta

2

Questo codice dà il codice di uscita a destra, e uccide il processo sopravvissuto:

#/bin/bash 

# trap for SIGTERM and set RET_VALUE to false 
trap "RET_VAL=false" SIGTERM 

MY_PID=$$ 
# Initialize RET_VALUE to true 
RET_VAL=true 

# This function will executed be in a separate job (see below) 
thread_listener() { 
    # Starts the long time job 
    ./longJob.sh & 
    PID=$! 
    # trap for sigterm and kill the long time process 
    trap "kill $PID" SIGTERM 
    echo waiting for $PID 
    echo Parent $MY_PID 
    # Send a SIGTERM to parent job in case of failure 
    wait $PID || kill $MY_PID 
    exit 
} 

echo $MY_PID 

# Runs thread listener in a separate job 
thread_listener & 
PID1=$! 

# Runs thread listener in a separate job 
thread_listener & 
PID2=$! 

wait 
# send sigterm to PID1 and PID2 if present 
kill $PID1 2> /dev/null 
kill $PID2 2> /dev/null 
# returns RET_VALUE 
$RET_VAL 

Vedere i commenti per una spiegazione del codice. Il trucco è avviare i lavori in grado di accettare o inviare il segnale al lavoro genitore, se necessario.

Il lavoro bambino inviare un segnale al genitore in caso di guasto del suo lavoro a tempo lungo e il genitore di inviare un segnale ai suoi bambino dopo l'attesa (è il genitore riceve un segnale l'attesa ritorna immediatamente)

1

Le recenti versioni di GNU Parallel si sono concentrate proprio su questo problema. Uccidere in esecuzione i bambini, se uno solo non riesce:

parallel --halt now,fail=1 'echo {};{}' ::: true false true true false 

Uccidi correre i bambini, se uno solo riesce:

parallel --halt now,success=1 'echo {};{}' ::: true false true true false 

uccidere i bambini in esecuzione, se il 20% non riesce:

parallel -j1 --halt now,fail=20% 'echo {#} {};{}' ::: true true true false true true false true false true 

Uccidi il bambino con i segnali TERM, TERM, TERM, KILL mentre aspetti 50 ms tra ogni segnale:

parallel --termseq TERM,50,TERM,50,TERM,50,KILL -u --halt now,fail=1 'trap "echo TERM" SIGTERM; sleep 1;echo {};{}' ::: true false true true false 
+0

Come si possono usare comandi più lunghi di una parola? per esempio 'parallel --halt now, fail = 1 'echo {}; {}' ::: true" echo 'hi' "' fallisce con '/ bin/bash: echo 'hi': comando non trovato' – edi9999

+0

It funziona se uso: 'parallel --halt now, fail = 1" echo {}; eval {} ":::" echo 'ho' "" echo 'hi' "' – edi9999

+0

Yup. O usate eval o utilizzate solo {}: 'parallel -halt now, fail = 1 {} :::" echo 'ho' "" echo 'hi' "' In genere sarà usato come: 'file di gatto | parallel --halt now, fail = 1' –