Сценарий оболочки, пока цикл чтения строки останавливается после первой строки

У меня есть следующий сценарий оболочки. Цель состоит в том, чтобы пройти через каждую строку целевого файла (путь которого является входным параметром сценария) и выполнить работу с каждой строкой. Теперь кажется, что он работает только с самой первой строкой в ​​целевом файле и останавливается после обработки этой строки. Что-то не так с моим сценарием?

#!/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

Обратите внимание на две модификации:

  1. становится read -u 9
  2. < $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 скрипт

  1. Элемент списка
Другие вопросы по тегам