Durchlaufen Sie die Ausgabe eines Befehls in bash ohne Subshell

9

Ich möchte die Ausgabe eines Befehls durchlaufen, ohne eine Unter-Shell zu erstellen oder eine temporäre Datei zu verwenden.

Die ursprüngliche Version meines Skripts sah folgendermaßen aus, funktioniert jedoch nicht, da eine Unterschale erstellt wird und der exitBefehl die Unterschale anstelle des erforderlichen Hauptskripts beendet. Es ist Teil eines viel größeren Skripts zum Konfigurieren des Richtlinienroutings und stoppt die Ausführung, wenn eine Bedingung erkannt wird, die dazu führt, dass das Routing fehlschlägt.

sysctl -a 2>/dev/null | grep '\.rp_filter' | while read -r -a RPSTAT ; do

  if [[ "0" != "${RPSTAT[2]}" ]] ; then
    echo >&2 "RP Filter must be disabled on all interfaces!"
    echo >&2 "The RP filter feature is incompatible with policy routing"
    exit 1
  fi
done

Eine der vorgeschlagenen Alternativen besteht darin, einen solchen Befehl zu verwenden, um die Unterschale zu vermeiden.

while read BLAH ; do echo $BLAH; done </root/regularfile

Daher scheint es mir, dass ich auch einen solchen Befehl verwenden sollte, um die Subshell zu vermeiden und trotzdem die Ausgabe des gewünschten Programms zu erhalten.

while read BLAH ; do echo $BLAH; done <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Leider führt die Verwendung dieses Befehls zu diesem Fehler.

-bash: syntax error near unexpected token `<(sysct ...

Ich bin wirklich verwirrt, da dies funktioniert.

cat <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Ich könnte die Ausgabe dieses Befehls in einer temporären Datei speichern und die Umleitung für die temporäre Datei verwenden, aber ich wollte das vermeiden.

Warum gibt mir die Umleitung einen Fehler und habe ich andere Optionen als das Erstellen einer temporären Datei?

Zoredache
quelle

Antworten:

13

Du hast einen verpasst <. Sollte sein:

while read BLAH ; do echo $BLAH; done < <(sysctl -a 2>/dev/null | grep '\.rp_filter')

Denken Sie <(sysctl -a 2>/dev/null | grep '\.rp_filter')daran, eine Datei zu sein.

Dogbane
quelle
Vielen Dank. Kann ich nur zu meiner Erbauung auf eine Manpage, Hilfe oder Webseite verweisen, die dies dokumentiert? Ich konnte Google nicht dazu bringen, mich auf etwas Nützliches hinzuweisen, während ich versuchte, danach zu suchen.
Zoredache
2
Google "Prozessersetzung". zB tldp.org/LDP/abs/html/abs-guide.html#PROCESS-SUB
dogbane
Es ist zu beachten, dass die <() - Ersetzung Dateideskriptoren verwendet und auf einigen Betriebssystemen temporäre Dateien transparent erstellt und verwendet.
ewindisch
@Zoredache: Einfach <(im Bash-Handbuch suchen (unter "Prozessersetzung").
Gilles 'SO - hör auf böse zu sein'
@ewindisch, wenn ein Tool transparent ein Tempfile erstellt, das in Ordnung ist, wollte ich einfach kein manuell erstellen, als ich mir ziemlich sicher war, dass ich es nicht brauchte.
Zoredache
0

Für ein paar weitere Alternativen, wenn jemand wieder hierher kommt ...

Abhängig von der Shell können Sie wahrscheinlich set -o errexitdie übergeordnete Shell beenden lassen, wenn ein Befehl (einschließlich einer Subshell) ungleich Null beendet wird, ohne in einem ifBlock oder einem nachgestellten &&oder ||wie in eingeschlossen zu sein

/bin/false || echo "ignoring error"

Sie können auch festlegen, dass die Unterschale dem übergeordneten Element mithilfe von kill und der Umgebungsvariablen $ PPID signalisiert, sofern verfügbar.

Oder Sie können den while-Block in eine Funktion verschieben und 0/1 zurückgeben (explizit 0 nach dem while-Block zurückgeben) und einfach Ihre Pipeline wie folgt ausführen sysctl | grep | function || exit. Ich nehme an, Sie könnten die Rückgaben auch in den Inline-Block einfügen, aber Funktionen sind Ihr Freund. ;)

dannysauer
quelle