SSH bewirkt, dass die while-Schleife stoppt

30

Ich habe es endlich geschafft, ein Problem, mit dem ich seit ein paar Wochen zu kämpfen habe, zu lösen. Ich verwende SSH mit "autorisierten Schlüsseln", um Befehle aus der Ferne auszuführen. Alles ist in Ordnung, außer wenn ich es in einer while-Schleife mache. Die Schleife wird beendet, nachdem eine Iteration mit einem ssh-Befehl abgeschlossen wurde.

Lange Zeit dachte ich, dies sei eine Art von Seltsamkeit, aber jetzt stellte ich fest, dass sich Bash tatsächlich identisch verhält.

Ein kleines Beispielprogramm, um das Problem zu reproduzieren. Dies stammt aus einer größeren Implementierung, die Snapshots erstellt und diese auf die Knoten in einem Cluster repliziert.

#!/bin/bash

set -x

IDTAG=".*zone"
MARKER="mark-$(date +%Y.%m.%d.%H.%M.%S)"
REMOTE_HOST=sol10-target
ZFSPARENT=rpool

ssh $REMOTE_HOST zfs list -t filesystem -rHo name,mounted $ZFSPARENT | grep "/$IDTAG    " > /tmp/actionlist

#for RMT_FILESYSTEM in $(cat /tmp/actionlist)
cat /tmp/actionlist | while read RMT_FILESYSTEM ISMOUNTED
do
   echo ${RMT_FILESYSTEM}@${MARKER}
   [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
   echo Remote Command Return Code: $?
done

(Beachten Sie, dass der Ausdruck grep search ein TAB-Zeichen enthält, wie in der Definition des Verhaltens der Option "-H" der ZFS-Liste festgelegt.)

In meinem Beispiel gibt es einige ZFS-Dateisysteme für das Stammverzeichnis, in denen sich für alle "Zonen" das Root-Dateisystem in einem Dataset befindet, das dem folgenden ähnlich ist

POOL / zonen / app1zone
POOL / zonen / gruppe2 / app2zone

etc.

Die obige Schleife sollte einen Schnappschuss für jeden der ausgewählten Datensätze erstellen, funktioniert jedoch nur mit dem ersten und wird dann beendet.

Dass das Programm die richtige Anzahl von Datensätzen findet, kann leicht durch Überprüfen der Datei "/ tmp / actionlist" bestätigt werden, nachdem das Skript vorhanden ist.

Wenn der Befehl ssh beispielsweise durch einen Echo-Befehl ersetzt wird, durchläuft die Schleife alle Eingabezeilen. Oder mein Favorit - stelle "Echo" vor den beleidigenden Befehl.

Wenn ich stattdessen eine for-Schleife verwende, funktioniert dies ebenfalls. Aufgrund der potenziellen Größe der Liste der Datensätze kann dies jedoch zu Problemen mit der maximalen erweiterten Befehlszeilenlänge führen.

Ich bin mir jetzt zu 99,999% sicher, dass nur die Schleifen mit ssh-Befehlen Probleme bereiten!

Beachten Sie, dass die Iteration, in der der Befehl ssh ausgeführt wird, abgeschlossen ist! Es ist, als ob die in die while-Schleife eingespeisten Daten plötzlich verloren gehen ... Wenn die ersten Eingabezeilen keinen ssh-Befehl ausführen, wird die Schleife fortgesetzt, bis der SSH-Befehl tatsächlich ausgeführt wird.

Auf meinem Laptop, auf dem ich dies teste, habe ich zwei Solaris 10-VMs mit nur zwei oder drei Beispieldatensätzen, aber das gleiche passiert auf den großen SPARC-Systemen, auf denen dies live gehen soll, und es gibt viele Datensätze.

Johan
quelle
7
SSH liest möglicherweise von der Standardeingabe und frisst Ihre actionlist. Versuchen Sie, die Standardeingabe von ssh auf/dev/null
BatchyX
Ich werde das versuchen. Ich möchte hinzufügen, dass das Einfügen von ssh in einen Wrapper nicht hilft ....
Johan
Du hast Recht. Wie konnte ich das nicht sehen?
Johan
@ BatchyX Ich denke, Ihr Kommentar eignet sich als Antwort.
ein Lebenslauf
Ich bin damit einverstanden, dass ich die Antwort "akzeptieren" möchte. Wenn @BatchyX sie als solche erneut veröffentlichen kann, werde ich dies tun.
Johan

Antworten:

43

SSH liest möglicherweise von der Standardeingabe und frisst Ihre Aktionsliste auf. Versuchen Sie, die Standardeingabe von ssh nach / dev / null umzuleiten:

ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER} </dev/null

Wenn while readich Befehle ausführe, die die Standardeingabe unter einer -style-Schleife stören könnten , möchte ich den gesamten Schleifenkörper in geschweifte Klammern setzen:

cat /tmp/uuoc | while read RMT_FILESYSTEM ISMOUNTED
do {
    echo ${RMT_FILESYSTEM}@${MARKER}
    [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
    echo Remote Command Return Code: $?
} < /dev/null; done
BatchyX
quelle
3
Double awesome für erstens die spezifische Verwendung der geschweiften Klammern ... die ich in 20 Jahren Scripting noch nie erlebt habe (zumindest nicht, dass ich mich erinnern kann.) Und für die uuoc-Schlussfolgerung. FWIW (und zu meiner eigenen Verteidigung) Ich mache manchmal eine Ausnahme und füge der Lesbarkeit halber redundante Katzenaussagen hinzu! Ich liebe dieses Forum, weil ich plötzlich wieder neue Dinge lerne! Speziell füge ich gerne Weiterleitungen an den Anfang von Zeilen wie in diesem Fall hinzu, aber in Foren, die die Angelegenheit zu verwirren scheinen, bekomme ich weniger nützliche Antworten!
Johan
Ich habe versucht, den Unterschied zwischen {...} und (...) ksh herauszufinden. Die Manpage sagt, dass {...} spezielle Schlüsselwörter sind, die nur am Anfang einer Befehlszeile erkannt werden. Aber es gibt noch einen weiteren Unterschied ... der ( </tmp/file [ -z "$SOMEVAR" ] && awk '{print "X", $0}' )sich auch bei geschweiften Klammern unterscheidet. Ich meine in Bezug auf die produzierte Ausgabe, nicht über die Tatsache, dass die schließende geschweifte Klammer in einer neuen Zeile sein muss ...
Johan
5
Außerdem hat OpenSSHs ssh die -nOption, das stdin aus / dev / null (effektiv) wieder zu öffnen.
Chris Johnsen
Gibt es Problemumgehungen für die Verwendung sudomit dem Befehl in der Schleife?
Bonh
Ich habe -n seit Ewigkeiten benutzt und irgendwann die Angewohnheit verloren ... und jetzt weiß ich wieder, warum ich es getan habe, nachdem ich ein wenig
Florian Heigl