Bash при преждевременном прерывании цикла чтения

Я уже давно бился головой об стену с этим.

Я хочу подключиться к набору машин по 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 }')

Сначала я подумал, что это проблема подоболочки, но, видимо, нет. Любая помощь, наряду с комментариями по стилю / содержанию, была бы принята с благодарностью! Я знаю, что собираюсь ударить себя, когда узнаю, почему ...

У меня аналогичная проблема с 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, "");

Thomas 08.11.2013 20:54
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
29
1
27 218
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

Не знаю, поможет ли это, но более чистый способ написания:

for nu in `ruby -e '(0..20).each { |i| puts i}'`; do
  tssh "MYBOXES$nu" 
done

Кроме того, если у вас есть GNU Coreutils, вы можете использовать seq 0 20 вместо команды ruby.

Jouni K. Seppänen 06.12.2008 19:34

@Paul Спасибо, это работает! Если бы я только знал, почему! Может быть, это все-таки проблема подоболочки. Определенно напоминает о предыдущих проблемах подоболочки, которые у меня были. @Jouni Я заменил некрасивую рубиновую часть на seq. Не знал об этой команде, спасибо. @All Есть какие-нибудь сведения о том, почему это исправление работает?

wopwop 06.12.2008 19:42

@Paul Это проблема ssh. Я сделаю пост

Foo Bah 11.08.2011 02:25

Я хочу, чтобы люди, голосующие против, объяснили, почему.

Paul Tomblin 28.03.2014 17:56

Цикл while..done также проблематичен при запуске внутри него ssh. Вместо этого использование петли for обычно решает проблему.

Peter 16.09.2014 15:02

Я также не уверен, почему это не удается, но мне нравятся 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 из процесса, поэтому, даже если это функция оболочки, он не может устанавливать переменные, которые сохраняются вне цикла.

Charles Duffy 09.08.2019 01:56

Другие вопросы по теме