Ответ 1
Не знаю, поможет ли это, но более чистый способ записи -
for nu in `ruby -e '(0..20).each { |i| puts i}'`; do
tssh "MYBOXES$nu"
done
Я стучал головой о стену какое-то время с этим.
Я хочу, чтобы SSH в набор машин и проверить, доступны ли они (прием соединений и не используется). Я создал небольшой script, tssh, который делает именно это:
#!/bin/bash
host=$1
timeout=${2:-1}
ssh -qo "ConnectTimeout $timeout" $host "[ \`who | cut -f1 | wc -l \` -eq 0 ] && exit 0 || exit 1"
Этот script работает правильно. Возврат 255, если возникла проблема с подключением, 1, если машина занята, и 0, если все хорошо. Если кто-то знает лучший способ сделать это, пожалуйста, дайте мне знать.
Итак, я попробую позвонить tssh на свой набор машин, используя цикл чтения while, и здесь все идет не так. Цикл завершается, как только 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
Если вы зацикливаете входные данные (например, файл со списком имен хостов) и вызываете SSH, вам необходимо передать параметр -n, иначе ваш цикл на основе ввода не будет выполнен.
while read host; do
ssh -n $host "remote command" >> output.txt
done << host_list_file.txt
В конструкции
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
Я столкнулся с этим сегодня - rsh и/или ssh могут сломать цикл чтения из-за него, используя stdin. Я помещаю -n в строку ssh, которая останавливает его от попытки использовать stdin, и он исправил проблему.
Я также не уверен, почему он терпит неудачу, но мне нравится xargs
и seq
:
seq 0 20 | xargs -n1 tssh MYBOXES
Как упоминал Кайи, это действительно излишний вызов ruby или seq (который не будет работать на BSD или OSX-машинах) только для вывода диапазона чисел. Если вы довольны использованием bash, вы можете:
for i in {0..20}; do
# command
done
Я считаю, что это должно работать для bash 2.05b и выше.
Я не могу поверить, что это результат 0, который нарушил ваш цикл, вы можете протестировать его, заменив команду tssh в цикле "/bin/true", которая также возвращает 0.
В отношении стиля я не понимаю, почему простая оболочечная оболочка script нуждается в рубине, perl, seq или jot или любом другом двоичном файле, который не находится на моем BSD.
вы также можете использовать встроенные оболочки для контурной конструкции, которая работает как минимум в ksh, bash:
for ((i=0; $i<=20; i++)); do
tssh "MYBOXES$i"
done
поговорите о "ограблении Питера, чтобы заплатить Павлу". Я много часов боролся, чтобы понять, почему мой ssh убил мое что-то в цикле чтения.
Еще один способ придерживаться цикла чтения и сохранить ваш ssh в то же время - использовать переключатель "-n", чтобы сделать STDIN на ssh/dev/null. Работает как прелесть для меня:
#!/bin/bash
[...]
something|while read host
do
ssh -nx ${host} fiddleAround
done
(Я всегда использую "-x", чтобы не тратить время на переговоры X в туннеле.)
Большинство ответов относятся к ssh. Другие команды также захватывают stdin и не имеют опции -n. Это должно касаться любых других команд. Это также должно работать для ssh.
while read x; do
# Make sure command does not hijack stdin
echo "" | command $x
done < /path/to/some/file