2017-01-17 10 views
2

eine Pipeline so etwas wie gegeben, möchte ich auf das Ergebnis von Schritt B. So etwas wie dieser Schritt C abhängig machen:Conditional Schritt in einer Pipeline

A | B | if [ $? -ne 0 ]; then C; else cat; fi | D | E 

Aber das scheint nicht zu funktionieren; C wird nie ausgeführt, egal was das Ergebnis von B. Ich suche nach einer besseren Lösung.

Ich verstehe, dass jeder Schritt einer Pipeline in einer eigenen Subshell ausgeführt wird. Daher kann ich eine Umgebungsvariable nicht an die Pipeline zurückgeben. Diese Pipeline befindet sich jedoch in einer parallelen Gnu-Umgebung, in der viele solcher Pipelines gleichzeitig ausgeführt werden und keiner von ihnen einen eindeutigen Wert kennt (sie verarbeiten nur den Datenstrom und müssen die Quelle nicht kennen, das Parent-Skript verarbeitet die erforderliche Trennung). Das bedeutet, dass die Verwendung einer temporären Datei auch nicht praktisch ist, da es keine Möglichkeit gibt, die Dateinamen eindeutig zu machen. Selbst $$ scheint mir keinen Wert zu geben, der in jedem der Schritte gleich ist.

+0

Sie könnten sich 'set -o pipefail' ansehen, aber realistischerweise müssen Sie nur Ihre Befehle zerlegen, anstatt eine einzige Pipeline zu verwenden. –

Antwort

4

Sie können eine Pipeline nicht konditional machen, da die Befehle parallel ausgeführt werden. Wenn C nicht ausgeführt wurden, bis B beendet wurde, wo würde B ausgegeben werden?

Sie müssen die Ausgabe B in einer Variablen oder einer temporären Datei speichern. Zum Beispiel:

out=$(mktemp) 
trap 'rm "$out"' EXIT 
if A | B > "$out"; then 
    C < "$out" 
else 
    cat "$out" 
fi | D | E 
+0

Das sieht nach der Lösung aus, die ich brauchte. Vielen Dank. –

+0

Setzen Sie es in eine Funktion, 'export -f' es, und es ist bereit für GNU Parallel –

+0

Anstelle der' mktemp' und der 'Falle' können Sie $ PARALLEL_TMP verwenden. –

1

Es ist eine logische Unmöglichkeit in der Art und Weise, das Problem angeben.

Angenommen, ein Rohr wie . Die Pipeline existiert speziell, weil wir wollen, dass B beginnt, von A zu lesen, bevor A beendet ist. Wenn also B beginnt (was wäre, wenn Ihre Bedingung ausgewertet wird), weiß A noch nicht, ob es scheitern oder Erfolg haben wird, also kann B es auch nicht wissen.

Was Sie tun können, ist ein Echo, als seine letzte Zeile, irgendeine Art von Statuscode. Dann kann B von Standard in lesen, speichern Sie die Eingabe (entweder als temporäre Datei, in eine Variable) und dann, sobald die letzte Zeile empfangen wird, überprüfen Sie den Status und dann Maßnahmen ergreifen.

Der andere Weg, es natürlich zu tun, ist A seine eigene Ausgabe zu speichern, und dann, wie es fertig ist, haben Sie die bedingte innerhalb A (und B aus der Pipeline zu beseitigen).

+0

Ah ... Natürlich ... Manchmal verirre ich mich in den Details. Danke, dass Sie mich daran erinnert haben, wie eine Pipeline funktioniert. –

Verwandte Themen