Я уже давно бился головой об стену с этим.
Я хочу подключиться к набору машин по SSH и проверить, доступны ли они (принимают соединения и не используются). Я создал небольшой скрипт tssh, который делает именно это:
#!/bin/bash
host=$1
timeout=${2:-1}
ssh -qo "ConnectTimeout $timeout" $host "[ \`who | cut -f1 | wc -l \` -eq 0 ] && exit 0 || exit 1"
Этот скрипт работает правильно. Возвращается 255, если возникла проблема с подключением, 1, если машина занята, и 0, если все в порядке. Если кто-нибудь знает, как это сделать лучше, дайте мне знать.
Итак, затем я пытаюсь вызвать tssh на моем наборе машин, используя цикл while read, и здесь все идет не так. Цикл завершается, как только tssh возвращает 0, и никогда не завершает полный набор.
while read nu ; do tssh "MYBOXES$nu" ; done < <(ruby -e '(0..20).each { |i| puts i }')
Сначала я подумал, что это проблема подоболочки, но, видимо, нет. Любая помощь, наряду с комментариями по стилю / содержанию, была бы принята с благодарностью! Я знаю, что собираюсь ударить себя, когда узнаю, почему ...





Не знаю, поможет ли это, но более чистый способ написания:
for nu in `ruby -e '(0..20).each { |i| puts i}'`; do
tssh "MYBOXES$nu"
done
Кроме того, если у вас есть GNU Coreutils, вы можете использовать seq 0 20 вместо команды ruby.
@Paul Спасибо, это работает! Если бы я только знал, почему! Может быть, это все-таки проблема подоболочки. Определенно напоминает о предыдущих проблемах подоболочки, которые у меня были. @Jouni Я заменил некрасивую рубиновую часть на seq. Не знал об этой команде, спасибо. @All Есть какие-нибудь сведения о том, почему это исправление работает?
@Paul Это проблема ssh. Я сделаю пост
Я хочу, чтобы люди, голосующие против, объяснили, почему.
Цикл while..done также проблематичен при запуске внутри него ssh. Вместо этого использование петли for обычно решает проблему.
Я также не уверен, почему это не удается, но мне нравятся xargs и seq:
seq 0 20 | xargs -n1 tssh MYBOXES
Я не могу поверить, что это был результат 0, который сломал ваш цикл, вы можете проверить это, заменив свою команду tssh в цикле на «/ bin / true», которая также возвращает 0.
Что касается стиля, я не понимаю, почему для простого цикла оболочки script нужны ruby, perl, seq или jot или любой другой двоичный файл, которого нет в моем * BSD.
в качестве альтернативы вы можете использовать встроенные оболочки для конструкции цикла, которая работает как минимум в ksh, bash:
for ((i=0; $i<=20; i++)); do
tssh "MYBOXES$i"
done
Я столкнулся с этим сегодня - rsh и / или ssh могут прервать цикл чтения while из-за использования stdin. Я поставил -n в строку ssh, которая не позволяет ему пытаться использовать stdin, и это устранило проблему.
Как упоминал Kaii, вызывать ruby или seq (которые не работают на машинах BSD или OSX) просто излишне, чтобы вывести диапазон чисел. Если вам нравится использовать bash, вы можете:
for i in {0..20}; do
# command
done
Я считаю, что это должно работать для bash 2.05b и выше.
Крис прав. Источником разрыва цикла был SSH с использованием stdin, однако оружие является правильным в использовании методологии цикла.
Если вы выполняете цикл ввода (например, файл со списком имен хостов) и вызываете SSH, вам необходимо передать параметр -n, иначе ваш цикл, основанный на вводе, завершится ошибкой.
while read host; do
ssh -n $host "remote command" >> output.txt
done << host_list_file.txt
поговорить о проблеме «ограбить Питера, чтобы заплатить Полу». Я часами пытался понять, почему мой ssh убивал мой цикл something | while read.
Другой способ сохранить цикл чтения while и одновременно использовать ssh - использовать переключатель «-n», чтобы сделать STDIN на ssh / dev / null. Для меня работает как шарм:
#!/bin/bash
[...]
something|while read host
do
ssh -nx ${host} fiddleAround
done
(Я также всегда использую "-x", чтобы не тратить время на согласование X в туннеле.)
В конструкции
something |
while read x; do
ssh ...
done
стандартный ввод, как видно из цикла while, является выводом something.
По умолчанию ssh читает стандартный ввод. Это позволяет вам делать такие вещи, как
cat id_rsa.pub | ssh new_box "cat - >> ~/.ssh/authorized_keys"
Теперь, с учетом сказанного, при чтении первого значения первая команда ssh прочитает весь ввод от something. Затем, когда ssh завершает работу, выходных данных не остается, и read останавливается.
Исправление - ssh -n ..., например.
cat /etc/hosts | awk '{print $2}' | while read x; do
ssh -n $x "do_something_on_the_machine"
done
Большинство ответов относятся к ssh. Другие команды также захватывают stdin и не имеют опции -n. Это должно касаться любых других команд. Это также должно работать для ssh.
while read x; do
# Make sure command does not hijack stdin
echo "" | command $x
done < /path/to/some/file
Это довольно неэффективно по сравнению с command "$x" </dev/null. echo "" | требует fork(), mkfifo() и т. Д .; и он перемещает command из процесса, поэтому, даже если это функция оболочки, он не может устанавливать переменные, которые сохраняются вне цикла.
У меня аналогичная проблема с Perl Net :: SSH :: Perl, @ Foo-Bah очень хорошо описал проблему, и решение состоит в том, чтобы добавить пустую строку в качестве параметра в cmd: metacpan.org/pod/Net::SSH::Perl#out-err-exit-ssh-cmd-cmd-std в my ($ stdout, $ stderr, $ exit) = $ ssh-> cmd ($ cmd, "");