Используя цикл с условием продолжения к ssh к нескольким серверам

Вы видите то, что происходит, и достигните желаемого поведения с ln опции. Используйте этот псевдоним для ln:

alias ln='\ln -vsn'

ln опции:

   -v, --verbose
          print name of each linked file
   -s, --symbolic
          make symbolic links instead of hard links
   -n, --no-dereference
          treat destination that is a symlink to a directory as if it were a normal file
77
05.01.2014, 01:46
6 ответов

ssh читает остальную часть Вашего стандартного входа.

while read HOST ; do … ; done < servers.txt

read чтения от stdin. < перенаправления stdin из файла.

К сожалению, команда, Вы пытаетесь выполнить также чтения stdin, таким образом, она завершает пищевую остальную часть Вашего файла. Вы видите его ясно с:

$ while read HOST ; do echo start $HOST end; cat; done < servers.txt 
start server1.mydomain.com end
server2.mydomain.com
server3.mydomain.com

Заметьте как cat поел (и отозвался эхом), оставление двумя строками. (Читал сделанный это как ожидалось, каждая строка будет иметь "запуск" и "конец" вокруг хоста.)

Почему делает for работа?

Ваш for строка не перенаправляет к stdin. (На самом деле это читает все содержание servers.txt файл в память перед первым повторением). Так ssh продолжает читать его stdin из терминала (или возможно ничто, в зависимости от того, как Ваш сценарий называют).

Решение

По крайней мере, в ударе, Вы можете иметь read используйте другой дескриптор файла.

while read -u10 HOST ; do ssh $HOST "uname -a" ; done 10< servers.txt
#          ^^^^                                       ^^

должен работать. 10 просто произвольный номер документа, который я выбрал. 0, 1, и 2 определили значения, и обычно вводные файлы начнут с первого доступного числа (таким образом, 3 будет рядом с использоваться). 10 таким образом достаточно высоко, чтобы остаться вне пути, но достаточно низко находиться под пределом в некоторых оболочках. Плюс он - круглое число...

Альтернативное решение 1:-n

Как McNisse указывает в его ответе, клиент OpenSSH имеет -n опция это будет препятствовать тому, чтобы он читал stdin. Это работает хорошо в особом случае ssh, но конечно другие команды могут испытать недостаток в этом — другая работа решений, независимо от которой команда ест Ваш stdin.

Альтернативное решение 2: второе перенаправление

Вы можете, по-видимому (как в, я попробовал его, это работает в моей версии Bash, по крайней мере...), делают второе перенаправление, которое выглядит примерно так:

while read HOST ; do ssh $HOST "uname -a" < /dev/null; done < servers.txt

Можно использовать это с любой командой, но это будет трудно, если Вы на самом деле захотите терминальный вход, идущий в команду.

98
27.01.2020, 19:31
  • 1
    , где делает число 10 произойти из? –  Martin Vegter 04.01.2014, 10:02
  • 2
    @MartinVegter я составил его. 0/1/2 являются stdin, stdout, и stderr. Можно выбрать любое число, которое Вы любите — удар позволяет Вам пойти довольно высоко, вероятно, до предела ОС. Другие оболочки могут ограничить Вас меньше... –  derobert 04.01.2014, 10:20
  • 3
    @MartinVegter я отредактировал для ответа на оба из комментариев. –  derobert 04.01.2014, 10:25
  • 4
    Другая альтернатива: exec 3<&0; while read HOST; do ssh $HOST "uname -a" <&3; done <servers.txt; exec 3<&- Это делает дескриптор файла 3 резервное копирование исходного stdin, затем использует его для stdin ssh, затем закрывает резервный FD при выполнении. Это работает над любой совместимой с POSIX оболочкой. @DougO' Neal –  Richard Hansen 08.01.2014, 20:49
  • 5
    -u опция не поддерживается POSIX и таким образом не должна использоваться для #!/bin/sh сценарии; использовать read HOST <&10 вместо этого. Кроме того, POSIX только требует оболочек к дескрипторам файла поддержки 0 до 9, таким образом, 10<servers.txt не может использоваться, если сценарий должен строго соответствовать. –  Richard Hansen 08.01.2014, 20:58

Поскольку derobert описывает ssh чтения Ваш stdin.

Для изменения этого поведения, можно добавить-n никакой ssh, чтобы препятствовать тому, чтобы он читал stdin.

ssh -n $HOST "uname -a"
31
27.01.2020, 19:31

Вы, вероятно, на самом деле были бы более обеспеченным использованием pssh из параллельного-ssh проекта.

pssh -h $hostfile -t $timeout -i $commands

-i интерактивные средства. pssh также идет с параллелью scp и параллелью rsync. То, что хорошо, - то, что это работает асинхронно и выполнит столько потоков, сколько Вы спрашиваете это к. Значение по умолчанию (не-i/interactive) должно произвести для разделения каталогов для stdout/stderr, который оно делает $outputdir/$hostname.

10
27.01.2020, 19:31

При находке этого вида задачи довольно часто необходимо попробовать Матрицу

Установите Матрицу, следующую инструкциям, большинство случаев, в которых Вы просто нуждаетесь sudo apt-get install fabric

Создайте названный файл fabfile.py со следующим кодом:

from fabric.api import env, run

env.hosts = ['server1.mydomain.com',
             'server1.mydomain.com',
             'server1.mydomain.com']

def mytask():
    run('uname -a')

Затем выполненный fab mytask даст Вам результат, который Вы хотите.

3
27.01.2020, 19:31

Это - более легкое использование команды как это:

for f in `cat servers.txt`; do ssh $f uname -a; done

Мне обычно нравится это:

for f in `cat servers.txt`; do echo "### $f ###"; ssh $f uname -a; done

echo должен видеть, какой сервер застревает или не может соединиться с ним.

1
27.01.2020, 19:31

Поскольку команда ssh принимает весь поток из стандартного ввода, подаваемого оператором while,

Вы можете использовать канал для переключения stdin ssh на другой источник:

echo "" | ssh ...

пример:

while read HOST ; do echo "" | ssh $HOST "uname -a" ; done < servers.txt

stdin ввод всех Команды ssh в цикле while должны быть переключены на другой источник.

2
20.08.2021, 12:59

Теги

Похожие вопросы