Kann ein Programm als nächstes in einer Pipeline den Exit-Code des vorherigen Programms sehen?

8

Ich möchte eine Pipeline solcher Bash-Skripte erstellen

prog1 | prog2

so dass prog2 den Exit-Code von prog1 sehen und basierend auf diesen Informationen anders handeln kann.

Ist das möglich?

Dan
quelle
Könnten Sie die Handlung als Teil Ihrer Frage anders ausarbeiten ?
devnull
Sie haben aufgrund der internen Pufferung, die zum Implementieren der Pipe verwendet wird, und wie und geplant, nur begrenzte Kontrolle darüber, wie weit prog2die prog1Exits beim Beenden fortgeschritten sind. prog1prog2
Chepner
Schauen Sie sich auch [In welcher Reihenfolge werden Piped-Befehle ausgeführt?] (Unix.stackexchange.com/q/37508) an
DK Bose

Antworten:

4

Die allgemeine Antwort lautet nein. Es ist möglich prog2, vor dem prog1Start zu beenden (dies kann natürlich nicht passieren, wenn prog2tatsächlich eine Eingabe gelesen wird, was Sie erwarten würden, wenn Sie sie in einer Pipeline verwenden). Es ist definitiv möglich prog2, vorher zu beenden prog1; Dies ist beispielsweise prog2der Fall, wenn ein Suchprogramm beendet wird, sobald eine Übereinstimmung gefunden wird. In diesem Fall sind prog1möglicherweise noch nicht alle Daten vollständig erstellt.

Es gibt keine direkte Möglichkeit prog2, den Exit-Status von Exit abzurufen prog1oder gar zu wissen, dass es beendet prog1wurde. Alles was prog2man wissen kann ist, dass prog1es sein Rohrende geschlossen hat, was es tun kann, ohne zu sterben.

Wenn Sie den Exit-Status von prog1von erhalten möchten prog2, gibt es zwei gängige Methoden: Sie können ihn in eine Datei schreiben oder über die Pipe senden. Das Senden des Ausgabestatus als letzte Zeile der weitergeleiteten Daten ist möglich. Sie müssen sicherstellen, dass die letzte Zeile erst verarbeitet wird, wenn Sie wissen, dass es sich um die letzte Zeile handelt, dh bis Sie versucht haben, die nächste Zeile zu lesen.

{ prog1; echo $?; } | 

Hier ist ein Beispiel, in dem die rechte Seite ein Textfilter ist, der jede Zeile mit dem Wort „Fehler“ rot färbt. Wenn die linke Seite ausfällt, wird die rechte Seite mit demselben Status beendet.

{ prog1; echo $?; } | awk '
    NR != 1 {
        if (line ~ /[Ee][Rr][Rr][Oo][Rr]/) print "\033[31m" line "\033[0m";
        else print line;
    }
    {line = $0}
    END {exit($0)}
'
Gilles 'SO - hör auf böse zu sein'
quelle
Ich habe versucht { command; echo ${PIPESTATUS[@]}; } | sort | ..., dass der Exit-Status im Stream an erster Stelle steht. Es ist alles sehr interessant!
@ illuminÉ Das würde nur funktionieren, wenn ${PIPESTATUS[@]}vor irgendetwas anderem in der Ausgabe von sortiert wird command. Wenn Sie commandeine Reihe von Zahlen ausdrucken oder beliebigen Text ausdrucken können, sind Sie in Schwierigkeiten: Sie können die Ausgabe nicht von der Statuszeile unterscheiden.
Gilles 'SO - hör auf böse zu sein'
Vielen Dank, tatsächlich gelingt es nur dann, einen Erfolgsstatus nach oben zu sortieren, wenn der Befehl keine 0 in seiner Ausgabe enthält lol. Tgif / s.
2

Obwohl Sie in einigen Sonderfällen (siehe die anderen Antworten) können, können Sie nicht in jedem Fall. Einige Filterprogramme werden einfach weiterlaufen, während andere die gesamte Ausgabe halten, sie in einem einzigen Druck auslösen und dann beenden.

Für ein Beispiel eines "einfach weitermachen" -Programms grepwird der Server wie gewohnt tail -f /var/log/some_log_file. Die Verwendung sortin einer Pipeline führt zu einem "Stillstand", da sortEingaben gesammelt werden, bis die vorgelagerte Pipe geschlossen wird. Die Verwendung xargsfügt eine weitere Komplikation hinzu: Werden die Programme von einem xargsTeil der Pipeline gestartet (es können viele Instanzen gestartet werden) oder nicht?

Bruce Ediger
quelle
-1, weil Sie für die Rationalisierung einer falschen Antwort positiv bewertet wurden.
Strg-Alt-Delor
@richard Huh? Die Antwort von Bruce ist richtig (obwohl der zweite Absatz etwas verwirrend ist).
Gilles 'SO - hör auf böse zu sein'
1

Die Antwort: Nicht direkt.

@terdon hat gezeigt, dass der Exit-Code des vorherigen Befehls in der Pipe als expliziter Parameter an den nächsten Befehl gesendet werden muss.

Denken Sie daran, dass die Pipe lediglich eine Zuordnung des STDOUT des vorherigen Befehls zum STDIN des nächsten Befehls ist. Exit-Codes werden nicht an STDOUT (oder STDERR) ausgegeben.

pepoluan
quelle
1
-1, weil Sie dafür gestimmt haben, eine falsche Antwort zu zitieren und nicht viel mehr zu sagen.
Strg-Alt-Delor
@richard fair genug ... Ich hätte es noch einmal überprüfen sollen ... das ist passiert, wenn ich mich
zwinge,
1

Alle in der Pipeline befindlichen Prozesse werden vor jedem Beenden gestartet. Daher prog2könnte es erforderlich sein, diese Informationen nach dem Start abzurufen. Außerdem müsste die Verarbeitung prog1unterbrochen werden, bis sie beendet wurde. Dies könnte die Pipe blockieren. Es scheint grundlegende Probleme zu geben, das zu tun, was Sie verlangen, nicht Betriebssystembeschränkungen.

Sie müssen wahrscheinlich eine temporäre Datei in Betracht ziehen oder das Ergebnis in eine Variable einfügen.

Beispiel für eine kleine Datenmenge unter Verwendung einer Variablen.

tmp=$(prog1)
if test "z$PIPESTATUS" == "z0"
then
   
else
   
fi
Strg-Alt-Delor
quelle
Es gibt eine Lücke in Ihrer Argumentation. prog2wird prog1im Allgemeinen gestartet, bevor der Vorgang abgeschlossen ist. Es kann jedoch eine Möglichkeit geben, den Ausgabestatus prog1während der Ausführung zu erhalten.
Gilles 'SO - hör auf böse zu sein'
0

Um Gilles 'Antwort zu beenden ,

(prog1; echo $? > /tmp/prog1.status) | prog2

ist ein Ansatz.  prog2könnte auch nicht

  • Lesen Sie die Standardeingabe bis zum Ende und lesen Sie dann /tmp/prog1.statusoder
  • Überprüfen Sie das Vorhandensein von /tmp/prog1.statusregelmäßig, während Sie die Standardeingabe lesen.
Scott
quelle