for
Петля отлично здесь. Но обратите внимание, что это связано с тем, что файл содержит имена компьютеров, которые не содержат никаких пробельных символов или символов-пробелов. for x in $(cat file); do …
не работает для итерации по строкам file
в общем, потому что оболочка сначала разбивает выходные данные команды в cat file
любом месте, где есть пробел, а затем обрабатывает каждое слово как шаблон глобуса, поэтому \[?*
дополнительно расширяется. Вы можете сделать for x in $(cat file)
безопасным, если вы работаете над этим:
set -f
IFS='
'
for x in $(cat file); do …
Связанное чтение: перебирать файлы с пробелами в именах? ; Как я могу читать построчно из переменной в Bash? ; Почему while IFS= read
используется так часто, а не IFS=; while read..
? Обратите внимание, что при использовании while read
безопасный синтаксис для чтения строк while IFS= read -r line; do …
.
Теперь давайте обратимся к тому, что не так с вашей while read
попыткой. Перенаправление из файла списка серверов распространяется на весь цикл. Поэтому при ssh
запуске его стандартный ввод поступает из этого файла. Клиент ssh не может знать, когда удаленное приложение может захотеть прочитать данные со своего стандартного ввода. Поэтому, как только клиент ssh замечает какой-либо ввод, он отправляет этот ввод на удаленную сторону. Затем сервер ssh готов передать эти входные данные удаленной команде, если он этого захочет. В вашем случае удаленная команда никогда не читает никаких входных данных, поэтому данные в конечном итоге отбрасываются, но клиентская сторона ничего об этом не знает. Ваша попытка echo
сработала, потому что echo
никогда не читает какой-либо ввод, он оставляет свой стандартный ввод в покое.
Есть несколько способов избежать этого. Вы можете указать ssh не читать со стандартного ввода с помощью -n
опции.
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
-n
Вариант на самом деле говорит ssh
перенаправить ввод из /dev/null
. Вы можете сделать это на уровне оболочки, и это будет работать для любой команды.
while read server; do
ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt
Способ заманчиво входа во избежание SSH пришествия из файла поставить переадресацию на read
команде: while read server </home/kenny/list_of_servers.txt; do …
. Это не будет работать, потому что при каждом выполнении read
команды файл будет открываться снова (поэтому он будет читать первую строку файла снова и снова). Перенаправление должно быть во всем цикле while, чтобы файл открывался один раз на протяжении цикла.
Общее решение состоит в том, чтобы обеспечить ввод для цикла в дескрипторе файла, отличном от стандартного ввода. Оболочка имеет конструкции для передачи ввода и вывода из одного номера дескриптора в другой. Здесь мы открываем файл в файловом дескрипторе 3 и перенаправляем read
стандартный ввод команды из файлового дескриптора 3. Клиент ssh игнорирует открытые нестандартные дескрипторы, поэтому все в порядке.
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
В bash read
команда имеет специальную опцию для чтения из другого файлового дескриптора, поэтому вы можете писать read -u3 server
.
Связанное чтение: файловые дескрипторы и сценарии оболочки ; Когда бы вы использовали дополнительный файловый дескриптор?