2013-12-13 4 views
5

Ich habe ein Problem zu prüfen, ob ein bestimmter Befehl in einer Befehlskette Multi-Rohr hat einen Fehler aus. Normalerweise ist das nicht schwer zu überprüfen, aber weder set -o pipefail noch Überprüfung ${PIPESTATUS[@]} funktioniert in meinem Fall. Das Setup ist wie folgt:Bash: Prüfung auf Exit-Status von Multi-Rohrbefehlskette

Hinweis-1: Der Befehl wurde gründlich getestet und funktioniert einwandfrei.

Jetzt will ich in einem Array die Ausgabe dieses Befehls speichern procdata genannt. So, ich habe:

declare -a procdata 
procdata=($(eval $cmd)) 

Hinweis-2: eval ist notwendig, weil sonst $snmpcmd mit einem invalid option -- <grepoption> Fehler wirft, die keinen Sinn macht, weil <grepoption> offensichtlich keine $snmpcmd Option. In diesem Stadium halte ich dies einen Fehler mit $snmpcmd, aber das ist eine andere Show ...

Wenn ein Fehler auftritt, wird procdata leer sein. Allerdings könnte es aus zwei verschiedenen Gründen leer sein: entweder, weil ein Fehler aufgetreten ist, während die Ausführung $snmpcmd (z Timeout) oder weil grep konnte nicht finden, was sie suchte. Das Problem ist, ich muss in der Lage sein, zwischen diesen beiden Fällen unterscheiden und sie getrennt behandeln.

Daher ist set -o pipefail keine Option, da es einen Fehler propagieren wird und ich kann nicht unterscheiden, welcher Teil der Pipe fehlgeschlagen ist. Auf der anderen Seite echo ${PIPESTATUS[@]} ist immer 0 nach procdata=($(eval $cmd)) obwohl ich viele Rohre habe!?. Wenn ich jedoch den gesamten Befehl direkt an der Eingabeaufforderung ausführe und unmittelbar danach echo ${PIPESTATUS[@]} aufruft, wird der Exit-Status aller Pipes korrekt zurückgegeben.

Ich weiß, ich könnte den Err-Stream an stdout binden, aber ich müsste heuristische Methoden verwenden, um zu überprüfen, ob die Elemente in procdata gültig sind oder Fehlermeldungen und ich riskiere falsch positive Ergebnisse. Ich könnte auch stdout auf /dev/null pipen und nur den Fehlerstrom erfassen und überprüfen, ob ${#procdata[@]} -eq 0. Aber ich müsste den Aufruf wiederholen, um die tatsächlichen Daten zu erhalten, und das ganze Kommando ist zeitaufwändig (ca. 3-5s). Ich würde es nicht zweimal anrufen wollen. Oder ich könnte eine temporäre Datei verwenden, um Fehler zu schreiben, aber ich würde es lieber ohne den Aufwand machen, Dateien zu erstellen/löschen.

Irgendwelche Ideen, wie ich diese Arbeit in bash machen?

Dank

PS:

$ echo $BASH_VERSION 
4.2.37(1)-release 

Antwort

3

Eine Reihe von Dingen hier:

(1) Wenn Sie sagen eval $cmd und versuchen, die Austrittswerte der Prozesse in der Pipeline in enthaltenen zu erhalten der Befehl $cmd würde echo "${PIPESTATUS[@]}"nur den Exit-Status für eval enthalten. Anstelle von eval müssen Sie die vollständige Befehlszeile angeben.

(2) Sie müssen die PIPESTATUS bekommen, während die Ausgabe der Pipeline an die Variablen zugewiesen wird. Der Versuch, das später zu tun, würde nicht funktionieren.


Als Beispiel kann man sagen:

foo=$(command | grep something | command2; echo "${PIPESTATUS[@]})" 

Dies erfasst die Ausgabe der Pipeline und die PIPESTATUS Array in die Variable foo.

Sie können die Befehlsausgabe in ein Array erhalten, indem er sagte:

result=($(head -n -1 <<< "$foo")) 

und die PIPESTATUS Array mit den Worten

tail -1 <<< "$foo" 
+0

ich den gleichen Gedanken hatte. Leider funktioniert es auch nicht, aber ich bin mir nicht sicher warum. Ich poste die genauen Befehle, weil ich das Offensichtliche nicht sehen könnte: – user3040975

+0

'local cmdargs =" - CHf, -m $ mibs -v $ snmp-c $ community $ agent "; local procdatacmd = "$ tblcmd $ cmdargs $ proc_table"; procdatacmd + = "| cut -d ',' -f $ Felder | grep -we -e | sort | uniq -c | sed 's/^ * \ | \" // g; s//,/g' ; echo $ {PIPESTATUS [@]} ". Dann tue ich:' deklariere -a procdata = ($ (head -n -1 <<< $ procdatacmd)) '. Die Ausgabe ist leer ... einfach nichts. und läuft und läuft auf dem Agenten. Was die ... – user3040975

+0

@ user3040975 Sie scheinen nicht _running_ einen Befehl in der Zeile oben zu sein. – devnull