Ich versuche, eine Textdatei zu lesen und mit jeder Zeile etwas zu tun, indem ich ein Bash-Skript verwende.
Ich habe also eine Liste, die so aussieht:
server1
server2
server3
server4
Ich dachte, ich könnte dies mit einer While-Schleife wie folgt durchlaufen:
while read server; do
ssh $server "uname -a"
done < /home/kenny/list_of_servers.txt
Die While-Schleife stoppt nach 1 Durchlauf und führt daher nur uname -a
aus auf server1
Mit einer for-Schleife mit cat funktioniert es jedoch gut:
for server in $(cat /home/kenny/list_of_servers.txt) ; do
ssh $server "uname -a"
done
Noch verblüffender für mich ist, dass dies auch funktioniert:
while read server; do
echo $server
done < /home/kenny/list_of_servers.txt
Warum stoppt mein erstes Beispiel nach der ersten Iteration?
Akzeptierte Antwort:
Der for
Schleife ist hier in Ordnung. Beachten Sie jedoch, dass dies daran liegt, dass die Datei Maschinennamen enthält, die keine Leerzeichen oder Globbing-Zeichen enthalten. for x in $(cat file); do …
funktioniert nicht, um die Zeilen von file
zu durchlaufen im Allgemeinen, weil die Shell zuerst die Ausgabe des Befehls cat file
aufteilt überall dort, wo es Leerzeichen gibt, und behandelt dann jedes Wort als Glob-Muster, also \[?*
werden weiter ausgebaut. Sie können for x in $(cat file)
erstellen sicher, wenn Sie daran arbeiten:
set -f
IFS='
'
for x in $(cat file); do …
Verwandte Lektüre:Dateien mit Leerzeichen im Namen durchlaufen?; Wie kann ich Zeile für Zeile aus einer Variablen in Bash lesen?; Warum wird while IFS= read
so oft verwendet, statt IFS=; while read..
? Beachten Sie dies bei Verwendung von while read
, lautet die sichere Syntax zum Lesen von Zeilen while IFS= read -r line; do …
.
Wenden wir uns nun dem zu, was mit Ihrem while read
schief geht Versuch. Die Umleitung aus der Serverlistendatei gilt für die gesamte Schleife. Wenn also ssh
läuft, kommt seine Standardeingabe aus dieser Datei. Der ssh-Client kann nicht wissen, wann die entfernte Anwendung möglicherweise von ihrer Standardeingabe lesen möchte. Sobald also der ssh-Client eine Eingabe bemerkt, sendet er diese Eingabe an die Remote-Seite. Der ssh-Server dort ist dann bereit, diese Eingabe an den Remote-Befehl weiterzugeben, falls er dies wünscht. In Ihrem Fall liest der Remote-Befehl niemals Eingaben, sodass die Daten verworfen werden, aber die Client-Seite weiß nichts davon. Ihr Versuch mit echo
hat funktioniert, weil echo
liest niemals irgendwelche Eingaben, es lässt seine Standardeingabe in Ruhe.
Es gibt einige Möglichkeiten, wie Sie dies vermeiden können. Sie können ssh mit -n
anweisen, nicht von der Standardeingabe zu lesen Option.
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
Das -n
Option teilt tatsächlich ssh
mit um seine Eingabe von /dev/null
umzuleiten . Sie können dies auf Shell-Ebene tun und es funktioniert für jeden Befehl.
while read server; do
ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt
Eine verlockende Methode, um zu vermeiden, dass die Eingabe von ssh aus der Datei kommt, besteht darin, die Umleitung auf read
zu setzen Befehl:while read server </home/kenny/list_of_servers.txt; do …
. Dies wird nicht funktionieren, da es dazu führt, dass die Datei jedes Mal erneut geöffnet wird, wenn der read
wird Befehl ausgeführt wird (es würde also die erste Zeile der Datei immer und immer wieder lesen). Die Umleitung muss auf der gesamten While-Schleife erfolgen, damit die Datei einmal für die Dauer der Schleife geöffnet wird.
Die allgemeine Lösung besteht darin, die Eingabe für die Schleife auf einem anderen Dateideskriptor als der Standardeingabe bereitzustellen. Die Shell verfügt über Konstrukte, um Eingaben und Ausgaben von einer Deskriptornummer zu einer anderen weiterzuleiten. Hier öffnen wir die Datei auf Dateideskriptor 3 und leiten den read
um Standardeingabe des Befehls aus Dateideskriptor 3. Der ssh-Client ignoriert offene Nicht-Standard-Deskriptoren, also ist alles in Ordnung.
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
In bash wird der read
Der Befehl hat eine spezielle Option zum Lesen aus einem anderen Dateideskriptor, sodass Sie read -u3 server
schreiben können .
Verwandte Lektüre:Dateideskriptoren und Shell-Scripting; Wann würden Sie einen zusätzlichen Dateideskriptor verwenden?