Сценарий оболочки, пока цикл чтения строки останавливается после первой строки
У меня есть следующий сценарий оболочки. Цель состоит в том, чтобы пройти через каждую строку целевого файла (путь которого является входным параметром сценария) и выполнить работу с каждой строкой. Теперь кажется, что он работает только с самой первой строкой в целевом файле и останавливается после обработки этой строки. Что-то не так с моим сценарием?
#!/bin/bash
# SCRIPT: do.sh
# PURPOSE: loop thru the targets
FILENAME=$1
count=0
echo "proceed with $FILENAME"
while read LINE; do
let count++
echo "$count $LINE"
sh ./do_work.sh $LINE
done < $FILENAME
echo "\ntotal $count targets"
В do_work.sh
Я бегу пару ssh
команды.
7 ответов
Проблема в том, что do_work.sh
работает ssh
команды и по умолчанию ssh
читает из стандартного ввода, который является вашим входным файлом. В результате вы видите только первую строку, обработанную, потому что ssh
потребляет оставшуюся часть файла, и ваш цикл while прерывается.
Чтобы предотвратить это, передайте -n
вариант вашего ssh
команда, чтобы сделать его читать из /dev/null
вместо стандартного ввода.
Очень простой и надежный обходной путь - изменить дескриптор файла, от которого команда получает ввод.
Это достигается двумя модификациями: аргументом и оператором перенаправления для.
В BASH значения дескриптора файла по умолчанию (т. Е. Значения для
-u
в) являются:
- 0 = стандартный ввод
- 1 = стандартный вывод
- 2 = stderr
Так что просто выберите другой неиспользуемый файловый дескриптор, например
9
просто для развлечения.
Таким образом, обходным путем будет следующее:
while read -u 9 LINE; do
let count++
echo "$count $LINE"
sh ./do_work.sh $LINE
done 9< $FILENAME
Обратите внимание на две модификации:
- становится
read -u 9
-
< $FILENAME
становится9< $FILENAME
Лучше всего я делаю это для всех
while
петли пишу в BASH. Если у вас есть вложенные циклы, используя
read
используйте разные файловые дескрипторы для каждого из них (9,8,7,...).
В общем, обходной путь, который не является специфичным для ssh
перенаправить стандартный ввод для любой команды, которая в противном случае может потреблять while
вход петли.
while read LINE; do
let count++
echo "$count $LINE"
sh ./do_work.sh "$LINE" </dev/null
done < "$FILENAME"
Добавление </dev/null
является решающим моментом здесь (хотя исправленные кавычки также несколько важны; см. также Когда обернуть кавычки вокруг переменной оболочки?).
Другой способ обхода, который несколько специфичен для ssh
чтобы убедиться, что любой ssh
команда имеет стандартный ввод, например, путем изменения
ssh otherhost some commands here
вместо этого читать команды из документа здесь, который удобно (для этого конкретного сценария) связывает стандартный ввод ssh
для команд:
ssh otherhost <<'____HERE'
some commands here
____HERE
Опция ssh -n предотвращает проверку состояния выхода ssh при использовании HEREdoc при передаче вывода в другую программу. Поэтому использование /dev/null в качестве стандартного ввода является предпочтительным.
#!/bin/bash
while read ONELINE ; do
ssh ubuntu@host_xyz </dev/null <<EOF 2>&1 | filter_pgm
echo "Hi, $ONELINE. You come here often?"
process_response_pgm
EOF
if [ ${PIPESTATUS[0]} -ne 0 ] ; then
echo "aborting loop"
exit ${PIPESTATUS[0]}
fi
done << input_list.txt
This was happening to me because I had set -e
and a grep
in a loop was returning with no output (which gives a non-zero error code).
Использование ssh -n ...
для запуска ваших удаленных команд через SSH.
#! /bin/bash
cat /root/host.txt | while read LINE
..
..
использование ssh -n -o StrictHostKeychecking=no
в do_work.sh
скрипт
- Элемент списка