SSH вызывает остановку цикла

30

Мне наконец удалось свести проблему, с которой я боролся в течение нескольких недель. Я использую SSH с «авторизованными ключами» для удаленного запуска команд. Все хорошо, кроме случаев, когда я делаю это в цикле. Цикл завершается после завершения любой итерации с помощью команды ssh.

Долгое время я думал, что это что-то странное, но теперь я обнаружил, что bash на самом деле ведет себя одинаково.

Небольшой пример программы для воспроизведения проблемы. Это извлечено из более крупной реализации, которая делает снимки и реплицирует их среди узлов в кластере.

#!/bin/bash

set -x

IDTAG=".*zone"
MARKER="mark-$(date +%Y.%m.%d.%H.%M.%S)"
REMOTE_HOST=sol10-target
ZFSPARENT=rpool

ssh $REMOTE_HOST zfs list -t filesystem -rHo name,mounted $ZFSPARENT | grep "/$IDTAG    " > /tmp/actionlist

#for RMT_FILESYSTEM in $(cat /tmp/actionlist)
cat /tmp/actionlist | while read RMT_FILESYSTEM ISMOUNTED
do
   echo ${RMT_FILESYSTEM}@${MARKER}
   [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
   echo Remote Command Return Code: $?
done

(Обратите внимание, что в выражении поиска grep есть символ TAB согласно определению поведения опции -H списка zfs.)

В моем примере есть несколько файловых систем ZFS для корня, где все «зоны» имеют свою корневую файловую систему в наборе данных с именем, аналогичным

БАССЕЙН / зоны / app1zone
БАССЕЙН / зоны / group2 / app2zone

и т.п.

Приведенный выше цикл должен создать моментальный снимок для каждого из выбранных наборов данных, но вместо этого он работает только для первого и затем завершается.

То, что программа находит нужное количество наборов данных, можно легко проверить, проверив файл «/ tmp / actionlist» после того, как скрипт существует.

Если команда ssh заменяется, например, командой echo, то цикл повторяется по всем входным строкам. Или мой любимый - добавь «эхо» к обидной команде.

Если я использую цикл for вместо него, он также работает, но из-за потенциального размера списка наборов данных это может вызвать проблемы с максимальной длиной расширенной командной строки.

Теперь я на 99,999% уверен, что только те циклы, в которых есть команды ssh, доставляют мне проблемы!

Обратите внимание, что итерация, в которой выполняется команда ssh, завершена! Это как если бы данные, переданные в цикл while, внезапно терялись ... Если первые несколько входных строк не выполняют команду ssh, то цикл продолжается до тех пор, пока он фактически не выполнит команду SSH.

На моем ноутбуке, где я тестирую это, у меня есть две виртуальные машины Solaris 10 только с двумя или тремя образцами наборов данных, но то же самое происходит в больших системах SPARC, где это должно быть запущено, и есть много наборов данных.

Johan
источник
7
SSH может читать со стандартного ввода, съедая ваше actionlist. Попробуйте перенаправить стандартный ввод ssh на/dev/null
BatchyX
Я попробую это. Я хочу добавить, что помещение ssh в обертку не помогает ....
Johan
Ты прав. Как я мог этого не видеть !?
Йохан
@BatchyX Я думаю, ваш комментарий считается ответом.
CVn
Я согласен, что хотел бы «принять» ответ, поэтому, если @BatchyX сможет опубликовать его как таковой, я сделаю это.
Йохан

Ответы:

43

SSH может читать из стандартного ввода, съедая ваш список действий. Попробуйте перенаправить стандартный ввод ssh в / dev / null:

ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER} </dev/null

Как правило, при запуске команд, которые могут мешать стандартному вводу в while readцикле -style, мне нравится заключать все тело цикла в фигурные скобки:

cat /tmp/uuoc | while read RMT_FILESYSTEM ISMOUNTED
do {
    echo ${RMT_FILESYSTEM}@${MARKER}
    [ "$ISMOUNTED" = "yes" ] && ssh $REMOTE_HOST zfs snapshot -r ${RMT_FILESYSTEM}@${MARKER}
    echo Remote Command Return Code: $?
} < /dev/null; done
BatchyX
источник
3
Удивительно, во-первых, за конкретное использование фигурных скобок ... с которыми я никогда не сталкивался за 20 лет написания сценариев (по крайней мере, не могу вспомнить). И за умный вывод. FWIW (и в свою защиту) Я иногда делаю исключение и добавляю избыточные выражения cat для удобства чтения! Мне нравится этот форум, потому что я снова узнаю что-то новое! В частности, мне нравится добавлять перенаправления в начало строк, как в этом случае, но на форумах это, кажется, запутывает вопрос, заставляя меня получать меньше полезных ответов!
Йохан
Я пытался выяснить разницу между {...} и (...) на man-странице ksh говорится, что {...} являются специальными ключевыми словами, распознаваемыми только в начале командной строки. Но есть и другое отличие ... ( </tmp/file [ -z "$SOMEVAR" ] && awk '{print "X", $0}' )отличается от фигурных скобок. Я имею в виду полученный результат, а не тот факт, что закрывающая фигурная скобка должна быть на новой строке ...
Йохан
5
Кроме того, в ssh OpenSSH есть -nопция, которая заставляет его (эффективно) заново открывать свой стандартный ввод из / dev / null.
Крис Джонсен
Какие-либо обходные пути для использования sudoс командой внутри цикла?
Бон
Раньше я использовал -n с давних времен и в какой-то момент утратил эту привычку .... и теперь я снова знаю, почему я это сделал, после небольшого времени, проведенного за копанием ...
Флориан Хейгл