Beenden einer Pipeline, wenn ein vorheriger Befehl fehlschlägt

Beenden einer Pipeline, wenn ein vorheriger Befehl fehlschlägt

Ich versuche, die Anzahl der laufenden und in der Warteschlange befindlichen PBS-Jobs zu überprüfen, indem ich die Ausgabe qstat -tn1eines bashSkripts analysiere. Bisher hat das funktioniert:

count ()
{
    qstat -tn1 | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

Ich sehe jedoch, dass dies qstatgelegentlich aus unbekannten Gründen fehlschlägt. In diesem Fall wird nichts stdoutund eine Fehlermeldung an ausgegeben stderrund das System wird mit einem Status ungleich Null beendet (ziemlich normal). Allerdings awkweiß es nicht, dass der qstatFehler aufgetreten ist, und druckt fröhlich 0 0für die leere Eingabe, die es erhalten hat. Dann readweist es beiden 0 zu Rund Qohne zu wissen, dass dies qstattatsächlich fehlgeschlagen ist.

  1. RIch muss und Qim BEGINBlock des Skripts mit 0 initialisieren awk, da möglicherweise keine laufenden Prozesse oder keine in die Warteschlange gestellten Prozesse vorhanden sind und ich 0für die Anzahl dieser Prozesse und nicht nur eine leere Zeichenfolge drucken muss.
  2. Ich könnte dies tun , wodurch das Beenden mit einem Status ungleich Null set -o pipefailmöglich wäre , der Beendigungsstatus jedoch nicht angezeigt wird und das Programm trotzdem ausgeführt wird und für die leere Eingabe druckt .countreadawk0 0
  3. Ich könnte es mit einer benannten Pipe und Unterprozessen versuchen, aber deren Verwaltung erscheint mir zu kompliziert und übertrieben.

Gibt es eine gute Möglichkeit, dem Anrufer countdas Erkennen des Fehlers zu ermöglichen?

Antwort1

Ich denke, das Einlesen counteiner Prozesssubstitution verhindert, dass Sie deren Rückgabestatus erhalten. Tun Sie es also nicht. Speichern Sie das Ergebnis stattdessen in einer Variablen oder verwenden Sie eine Pipe.

count=$(count)
if [ $? -eq 0 ]; then
  read -r R Q <<<"$count"

oder

set -o pipefail
if count | { read -r R Q; … }

Eine andere Möglichkeit besteht darin, die Variable zu verwenden, PIPESTATUSum den Rückgabestatus des ersten Befehls zu überprüfen.

count=$(qstat -tn1 | awk …)
if ((${PIPESTATUS[0]} == 0)); then
  read P Q

Alternativ können Sie dafür sorgen, dass awk etwas Bestimmtes ausgibt (z. B. nichts), wenn seine Eingabe leer ist.

awk '
    BEGIN { R = 0; Q = 0; }
    $10 == "R" { R++ }
    $10 == "Q" { Q++ }
    END { if (NR) print R, Q }'

Ob die Eingabe eines Befehls leer ist, können Sie testen mit ifnefrommehrutilsoderandere Methoden. Aber da Sie eine Weiterleitung in awk durchführen, können Sie dies auch gleich in dem awk-Skript tun, das Sie bereits haben.

Wenn Sie den Rückgabestatus des Befehls benötigen qstat, können Sie ihn als zusätzliche Eingabezeile an awk übermitteln. Sorgen Sie zur einfacheren Analyse dafür, dass die letzte Zeile ein eindeutiges Format hat.

{
  qstat -tn1
  echo exit_code = $?
} | awk '
    /^exit_code = / { status = $3 }
    END { if (status == 0) print Q, R }
'

Antwort2

Das:

count ()
{
    { qstat -tn1 || echo "EPIC FAIL" } | awk '
        BEGIN { R = 0; Q = 0; }
        $10 == "R" { R++ }
        $10 == "Q" { Q++ }
        END { print R, Q }'
}

if read -r R Q < <(count)
    ...

Bei qstatErfolg wird die Ausgabe an gesendet awk. Wenn qstatein Status ungleich Null zurückgegeben wird, wird der Text „EPIC FAIL“ an gesendet awk.

Dies ist nur ein Beispiel. Ersetzen Sie das Echo durch etwas Passendes, das Sie innerhalb awkoder mit verarbeiten können if read.

verwandte Informationen