Bash: Überprüfen der exit-status des multi-pipe-Kommando-Kette
Ich habe ein problem, die Prüfung, ob ein bestimmter Befehl in einem multi-pipe-Befehl Kette hat einen Fehler auslösen. In der Regel ist dies nicht schwer zu überprüfen, aber weder set -o pipefail
noch durch ${PIPESTATUS[@]}
funktioniert in meinem Fall. Das setup ist wie folgt:
cmd="$snmpcmd $snmpargs $agent $oid | grep <grepoptions> for_stuff | cut -d',' f$fields | sed 's/ubstitute/some_other_stuff/g'"
Hinweis-1: Der Befehl wurde gründlich getestet und funktioniert einwandfrei.
Jetzt, ich möchten, speichern Sie die Ausgabe des Befehls in ein array mit dem Namen procdata
. Also, ich habe:
declare -a procdata
procdata=( $(eval $cmd) )
Hinweis-2: eval
ist notwendig, weil sonst $snmpcmd
wirft mit einem invalid option -- <grepoption>
Fehler, die keinen Sinn macht, weil <grepoption>
ist nicht ein $snmpcmd
option offensichtlich. In diesem Stadium halte ich das ein Fehler bei $snmpcmd
aber das ist eine andere show...
Wenn ein Fehler verwickelt, procdata
leer. Es könnte aber auch leer sein, für zwei verschiedene Ursachen haben: entweder da ist ein Fehler aufgetreten während der Ausführung der $snmpcmd
(z.B. timeout), oder weil grep
konnte nicht finden, was es suchte. Das problem ist, ich muss in der Lage sein, zu unterscheiden zwischen diesen beiden Fällen und diese separat behandeln.
So set -o pipefail
ist keine option, da es zu propagieren, die alle Fehler und ich kann nicht unterscheiden, welcher Teil der pipe ist fehlgeschlagen. Auf der anderen Seite echo ${PIPESTATUS[@]}
ist immer 0
nach procdata=( $(eval $cmd) )
obwohl ich viele Rohre!?. Doch wenn ich die ausführen den ganzen Befehl direkt an der Eingabeaufforderung, und rufen Sie echo ${PIPESTATUS[@]}
sofort nach, es gibt den exit-status aller Leitungen korrekt.
Ich weiß, ich könnte binden die err-stream auf stdout aus, aber ich hätte zu verwenden heuristische Methoden, um zu überprüfen, ob die Elemente in procdata
gültig sind oder Fehlermeldungen und ich laufen das Risiko von false positives. Ich könnte auch pipe stdout zu /dev/null
und erfassen nur den error-stream und überprüfen Sie, ob ${#procdata[@]} -eq 0
. Aber ich würde wiederholen Sie den Anruf, um die tatsächlichen Daten, und der ganze Befehl ist an der Zeit teuer (ca. 3-5s). Ich würde nicht wollen, nennen Sie es zweimal. Oder könnte ich eine temporäre Datei zu schreiben, die Fehler, aber ich würde lieber tun Sie es, ohne den overhead für das erzeugen/löschen von Dateien.
Irgendwelche Ideen, wie ich kann machen diese Arbeit in der bash?
Dank
P. S.:
$ echo $BASH_VERSION
4.2.37(1)-release
Du musst angemeldet sein, um einen Kommentar abzugeben.
Eine Reihe von Dingen hier:
(1) Wenn Sie sagen
eval $cmd
und versuchen, den Ausgang Werte der Prozesse in der pipeline enthaltenen Befehl$cmd
,echo "${PIPESTATUS[@]}"
enthalten würde nur der exit-status füreval
. Statteval
würden Sie brauchen, um liefern die komplette Befehlszeile.(2), die Sie benötigen, um die
PIPESTATUS
während die Zuordnung der Ausgang der pipeline auf die variable. Der Versuch, das zu tun, später würde das nicht funktionieren.Als ein Beispiel, Sie können sagen:
Dieser erfasst den Ausgang der pipeline und die
PIPESTATUS
array in die variablefoo
.Können Sie die Ausgabe des Befehls in ein array, indem Sie sagen:
und die
PIPESTATUS
array, indem Sie sagen,local cmdargs="-CHf , -m$mibs -v$snmpver -c$community $agent"; local procdatacmd="$tblcmd $cmdargs $proc_table "; procdatacmd+="| cut -d',' -f$fields | grep -w e <proc1> -e <proc2> | sort | uniq -c | sed 's/^ *\|\"//g;s/ /,/g' ; echo ${PIPESTATUS[@]}"
. Dann weiß ich:declare -a procdata=( $(head -n -1 <<< $procdatacmd) )
. Die Ausgabe ist leer ... einfach nichts. <proc1> und <proc2> sind und laufen auf den Agenten. Was die ...foo=$($procdatacmd); procdata=($(head -n -1 << $foo))
nicht arbeiten: "/usr/bin/snmptable: ungültige option -- "'". Ich habe einen "-x" wechseln, um den aktuellen Befehl. Einfügen und ausführen über die Eingabeaufforderung funktioniert einwandfrei...foo=$($procdatacmd);
. Um noch mehr klar, müssen Sie den vollständigen Befehl anstelle einer variable an Stelle von$procdatacmd
.temp=$($tblcmd $cmdargs $proc_table | cut -d',' -f$fields | $( get_pgreplist ) | sort | uniq -c | sed 's/^ *\|\"/ /g;s/ /,/g' ; echo ${PIPESTATUS[@]})
. Jetztprocdata=( $(head -n -1 <<< $temp) )
etwas tut, Ausgänge nichts, obwohlprocdata=( $(head <<< $temp) )
Ausgänge die richtigen Werte (Zeile für Zeile)?! Ich bin verwirrt ...head -n -1 <<< "$temp"
undtail -1 <<< "$temp"
ersten das Ergebnis zu sehen. Und bitte Zitat die Variablen wie angegeben.temp
wie Sie es mitfoo
und versuchen, es zu Lesen inprocdata
wie Sie Lesen es inresult
. Einfach zu sagenhead -n -1 <<< "$temp"
undtail -1 <<< "$temp"
nach obentemp
Zuordnung geben Sie den folgenden Fehler: "head: cannot open '1 0 1 0 0 0' for reading: No such file or directory" und "Schwanz: kann nicht öffnen" 1 0 1 0 0 0' for reading: No such file or directory" ...1 0 1 0 0 0
zeigen, dass die exit-codes erfasst wurden. Einfach sagenecho "${temp}"
um zu sehen, was es gibt.echo "${temp}"
Ausgänge10,httpd,runnable 64,nfsd,runnable 0 0 0 0 0 0
. Suche fürhttp
Ausgänge0 0 1 0 0 0
Anzeige-Fehler zu grep, während eine gefälschte IP wird mir1 0 1 0 0 0
als gedacht. Nochmals vielen Dank! Leider kann ich nicht abstimmen dieser mangelnden Ruf ...