2015-08-27 4 views
5

Ich habe die folgende Frage gesehen: Bash run two commands and get output from both die fast auf meine Bedürfnisse reagiert.Mehrere Befehle parallel ausführen und immer dann zurückkehren, wenn einer von ihnen fehlschlägt oder alle erfolgreich sind

Der Befehl wait blockiert jedoch, dh wenn Befehl 2 fehlschlägt, bevor Befehl 1 erfolgreich ist, kehrt der Befehl nicht zurück, wenn Befehl 2 fehlschlägt, sondern nur, wenn Befehl 1 erfolgreich ist.

Ist es möglich, mehrere Befehle parallel auszuführen und 1 zurückzugeben, wenn einer von ihnen fehlschlägt, und 0 zurückzugeben, wenn alle erfolgreich sind (und so schnell wie möglich zurückzukehren)?

Noch besser wäre es, wenn das mit Standardbefehlen (wie xargs oder parallel) möglich ist, aber auch ok, wenn es mit bash geschrieben wird.

+0

Wenn einer der Befehle fehlschlägt, möchten Sie den anderen töten, bevor Sie ihn zurückgeben oder den anderen laufen lassen? – Alepac

+0

Ja, das wäre besser (den anderen Befehl zu töten) – edi9999

+0

Haben Sie [diesen Thread] (http://stackoverflow.com/questions/9145528/barrier-in-bash-can-it-be-done-easily) angeschaut) Es simuliert das Verhalten einer Barier in Bash – Aserre

Antwort

2

Dieser Code gibt den richtigen Exit-Code, und tötet die Überlebenden Prozess:

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

die Kommentare für eine Erklärung des Codes anzeigen. Der Trick besteht darin, Jobs zu starten, die in der Lage sind, bei Bedarf Signal an den übergeordneten Job zu senden oder zu senden.

Das Kind Job ein Signal an die Eltern im Falle eines Ausfalls seiner langen Zeitjob und das Mutter senden ein Signal an seine Childs nach der Wartezeit senden (es die Eltern ein Signal, um die Wartezeit kehrt sofort zu erhalten)

1

Die jüngsten Versionen von GNU Parallel haben sich genau auf dieses Problem konzentriert. Töten Kinder laufen, wenn ein einziger fehlschlägt:

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

Tötung Kinder laufen, wenn ein einzelner gelingt:

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

Tötung laufen Kinder, wenn 20% fehlschlägt:

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

Töte das Kind mit den Signalen TERM, TERM, TERM, KILL, während zwischen den einzelnen Signalen 50 ms gewartet werden:

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

Wie können Sie Befehle länger als ein Wort verwenden? zum Beispiel 'parallel --halt now, fail = 1 'echo {}; {}' ::: true" echo 'hi' "' scheitert mit '/ bin/bash: echo 'hi': Befehl nicht gefunden' – edi9999

+0

It funktioniert, wenn ich folgendes benutze: 'parallel --halt now, fail = 1 'echo {}; eval {}" ::: "echo' ho '" "echo' hi '" ' – edi9999

+0

Yup. Benutze entweder eval oder benutze nur {}: 'parallel --halt now, fail = 1 {} :::" echo 'ho' "" echo 'hi' "' Normalerweise wird es verwendet als: 'cat file | parallel --halt jetzt, scheitern = 1 –

Verwandte Themen