for
Pętli jest tutaj dobrze. Należy jednak pamiętać, że dzieje się tak, ponieważ plik zawiera nazwy maszyn, które nie zawierają żadnych białych znaków ani znaków globowania. generalnie for x in $(cat file); do …
nie działa iteracja po liniach file
, ponieważ powłoka najpierw rozdziela dane wyjściowe od polecenia w cat file
dowolnym miejscu spacji, a następnie traktuje każde słowo jako wzorzec globalny, więc \[?*
są one dalej rozwijane. Możesz for x in $(cat file)
zabezpieczyć się, jeśli nad tym pracujesz:
set -f
IFS='
'
for x in $(cat file); do …
Czytanie pokrewne: Pętli w plikach ze spacjami w nazwach? ; Jak mogę odczytać wiersz po wierszu ze zmiennej w bash? ; Dlaczego jest while IFS= read
używany tak często, a nie IFS=; while read..
? Zauważ, że podczas używania while read
bezpieczna składnia do odczytu linii to while IFS= read -r line; do …
.
Teraz przejdźmy do tego, co idzie nie tak z Twoją while read
próbą. Przekierowanie z pliku listy serwerów dotyczy całej pętli. Kiedy ssh
działa, jego standardowe wejście pochodzi z tego pliku. Klient ssh nie może wiedzieć, kiedy zdalna aplikacja może chcieć czytać ze swojego standardowego wejścia. Gdy tylko klient ssh zauważy jakieś dane wejściowe, wysyła je na stronę zdalną. Serwer ssh jest wtedy gotowy do wprowadzenia tych danych wejściowych do polecenia zdalnego, jeśli tego chce. W twoim przypadku zdalne polecenie nigdy nie odczytuje żadnych danych wejściowych, więc dane zostają odrzucone, ale strona klienta nic o tym nie wie. Twoja próba echo
zadziałała, ponieważ echo
nigdy nie czyta żadnych danych wejściowych, pozostawia swoje standardowe dane w spokoju.
Jest kilka sposobów, aby tego uniknąć. Z -n
opcją możesz powiedzieć ssh, aby nie czytał ze standardowego wejścia .
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
Ta -n
opcja mówi ssh
o przekierowaniu danych wejściowych /dev/null
. Możesz to zrobić na poziomie powłoki, i zadziała dla każdego polecenia.
while read server; do
ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt
Sposób kuszące, aby uniknąć wejścia ssh pochodzące z pliku jest umieścić przekierowanie na read
polecenia: while read server </home/kenny/list_of_servers.txt; do …
. To nie zadziała, ponieważ powoduje, że plik jest otwierany ponownie za każdym razem, gdy read
komenda jest wykonywana (aby w kółko czytał pierwszy wiersz pliku). Przekierowanie musi odbywać się w całej pętli while, aby plik był otwierany jeden raz na czas trwania pętli.
Ogólnym rozwiązaniem jest zapewnienie wejścia do pętli w deskryptorze pliku innym niż wejście standardowe. Powłoka ma konstrukcje do przesyłania danych wejściowych i wyjściowych z jednego numeru deskryptora do drugiego. Tutaj otwieramy plik na deskryptorze pliku 3 i przekierowujemy read
standardowe wejście polecenia z deskryptora pliku 3. Klient ssh ignoruje otwarte niestandardowe deskryptory, więc wszystko jest w porządku.
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
W bash read
polecenie ma określoną opcję odczytu z innego deskryptora pliku, więc możesz pisać read -u3 server
.
Literatura pokrewna: Deskryptory plików i skrypty powłoki ; Kiedy użyjesz dodatkowego deskryptora pliku?
Powinieneś użyć
while
, niefor
. Aby uniknąć przełykania poleceń przez standardowe wejście w takiej pętli, wystarczy po prostu użyć innego deskryptora pliku :Aby uzyskać więcej informacji
help [r]ead
( naprawdę ) i inny artykuł wyjaśniający dlaczego .źródło
-u
flaga? Nie jestem pewien, na jakiej stronie man powinienem to sprawdzić.help read
-help
to polecenie pobierania odpowiednikaman
stron dla wbudowanych powłok.W twoim pierwszym kodzie
ssh
„wykradnie” STDIN zwhile
. Dodaj-n
opcję, abyssh
tego uniknąć. Odman ssh
:źródło
for
pętla odbiera dane jako parametr, a nie jako dane wejściowe.Domyślna standardowa obsługa wejścia
ssh
opróżnia pozostałą linię z pętli while.Aby uniknąć tego problemu, zmień, skąd problematyczne polecenie odczytuje standardowe dane wejściowe. Jeśli do komendy nie trzeba przekazywać żadnych standardowych danych wejściowych, należy odczytać standardowe dane wejściowe ze specjalnego
/dev/null
urządzenia.źródło