.png)
Wie kann ich Befehle weiterleiten und im Skript entscheiden, ob die Pipe unterbrochen werden soll oder nicht?
Es ist ähnlich wiediese Frage. Aber stattdessen awk
möchte ich mein eigenes Skript verwenden:
check_ip | update_bind9
check_ip
sollte die externe IP ( curl -s ifconfig.co
) finden und sie mit der in einer Datei ( ~/.ip
) gespeicherten IP vergleichen.
Hier ist die Hauptfrage:
Wenn sich die IP geändert hat, check_ip
sollte die IP durch die Pipe geleitet werden. Wenn nicht, sollte die Pipe unterbrochen werden.
Unterbricht check_ip
das die Pipe oder update_bind9
wird der Anruf ignoriert, wenn er nicht mit der IP aufgerufen wird?
Ich habe einige Tests durchgeführt und aufgerufen: check_ip | echo "ok"
.
Ich habe versucht exit 0
, exit 1
, , return true
, return false
. Habe versucht set -e
, . Ohne Erfolg.
Antwort1
Alle Komponenten einer Pipelinegleichzeitig starten– Der zweite Befehl wird immer gestartet, unabhängig davon, was im ersten Befehl passiert.
Es ist also der zweite Befehl, der mit einer leeren Standardeingabe umgehen muss.
Allerdings würde ich sagen, dass Rohre hierfür ohnehin keine gute Wahl sind.
(Vielleicht verwechseln Sie |
(Pipe) mit ||
(Boolesches ODER)? LetzteresIstwird häufig als kürzere Alternative zu if/then verwendet, z. B. x || y
ruft y nur auf, wenn x fehlschlägt – und ähnlich: x && y
ruft y nur auf, wenn x erfolgreich ist.)
Im Allgemeinen sollten Sie einen if/then-Block verwenden. Wenn beispielsweise check_ip
selbst 0 (Erfolg) zurückgibt, wenn die Adressen unterschiedlich sind, aber 1 (Fehler), wenn sie gleich sind, würde es folgendermaßen aussehen:
if addr=$(check_ip); then
echo "$addr" | update_bind9
fi
Alternativ sähe es folgendermaßen aus, wenn update_bind9 die Adresse selbständig ermitteln kann (ohne stdin zu lesen):
if check_ip_needs_updating; then
update_bind9
fi
Antwort2
Diese andere Antwortist gut. Wenn Sie jedoch wirklich bedingt weiterleiten müssen, finden Sie möglicherweiseifne
nützlich:
ifne
führt den folgenden Befehl genau dann aus, wenn die Standardeingabe nicht leer ist.
In Ihrem Fall wird es so sein check_ip | ifne update_bind9
.
Höchstwahrscheinlich ifne
ist es in Ihrem Linux nicht standardmäßig installiert. In meinem Debian 10 ist es im moreutils
Paket enthalten. Man könnte meinen, ein zusätzliches Tool wäre völlig überflüssig, da wir die Ausgabe check_ip
in einer Variablen speichern und bedingt wiederverwenden können, wie in der erwähnten Antwort:
if addr=$(check_ip); then echo "$addr" | update_bind9 fi
Die Bedingung kann sein [ -n "$addr" ]
, was auch immer; wichtig ist, dass wir eine Variable verwenden. Code wie der obige kann Ihr Problem lösen, aber im Allgemeinen gibt es mindestens drei Probleme damit. Nehmen Sie an, command1 | command2
statt check_ip | update_bind9
. Die Lösung wird verallgemeinert zu:
if foo=$(command1); then
echo "$foo" | command2
fi
Und dann:
foo=$(command1)
entfernt alle nachfolgenden Zeilenumbrüche aus der Ausgabe voncommand1
. Dannecho "$foo"
(oderprintf … "$foo"
) fügt genau ein Zeilenumbruchzeichen (bzw. eine feste Anzahl davon) hinzu. Aus diesem Grundcommand2
erhalten Sie möglicherweise nicht die exakte Ausgabe voncommand1
.command1
kann eine Ausgabe erzeugen, die NUL-Zeichen enthält. Bash kann NUL nicht in einer Variablen speichern (die meisten Shells können das nicht; zsh kann das). Wenn NUL erscheint,command2
wird nicht die genaue Ausgabe von erhaltencommand1
.command1
kann einen riesigen oder sogar endlosen Datenstrom erzeugen, sodass das Speichern in einer Variablen möglicherweise nicht möglich ist.
Die Verwendung einer Datei anstelle der Variablen löst alle Probleme außer dem letzten. command1 | ifne command2
ist gegen alle drei Probleme immun.