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
.
Связанное чтение: файловые дескрипторы и сценарии оболочки ; Когда бы вы использовали дополнительный файловый дескриптор?
Вы должны использовать
while
, а неfor
. Чтобы избежать команд, поглощающих стандартный ввод в таком цикле, просто используйте другой файловый дескриптор :Для получения дополнительной информации,
help [r]ead
(на самом деле ) и еще одна статья, объясняющая почему .источник
-u
флаг? Я не уверен, на какой справочной странице я должен это посмотреть.help read
-help
это команда для получения эквивалентаman
страниц для встроенных команд оболочки.В вашем первом коде
ssh
будет «украсть» STDIN изwhile
. Добавьте-n
опцию,ssh
чтобы избежать этого. Отman ssh
:источник
for
цикл получает данные как параметр, а не как ввод.Стандартная стандартная обработка ввода
ssh
выводит оставшуюся строку из цикла while.Чтобы избежать этой проблемы, измените, откуда проблемная команда читает стандартный ввод. Если в команду не нужно передавать стандартный ввод, считайте стандартный ввод со специального
/dev/null
устройства.источник