Podczas gdy pętla zatrzymuje odczyt po pierwszej linii w Bash

Mam następujący skrypt powłoki. Celem jest zapętlenie każdej linii pliku docelowego (którego ścieżka jest parametrem wejściowym do skryptu)i wykonanie pracy z każdą linią. Wygląda na to, że działa tylko z pierwszą linią w pliku docelowym i zatrzymuje się po przetworzeniu tej linii. Czy jest coś nie tak z moim scenariuszem?

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

W do_work.sh uruchamiam kilka ssh poleceń.

Author: oguz ismail, 2012-12-10

5 answers

Problem polega na tym, że do_work.sh uruchamia ssh polecenia i domyślnie ssh czyta ze standardowego wejścia, które jest twoim plikiem wejściowym. W rezultacie widzisz tylko pierwszą linię przetwarzaną, ponieważ ssh pochłania resztę pliku, a pętla while kończy się.

Aby temu zapobiec, przekaż opcję -n do polecenia ssh, Aby odczytać ją z /dev/null zamiast standardowego wejścia.

 192
Author: dogbane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-10 11:56:30

Bardziej ogólnie, obejściem, które nie jest specyficzne dla ssh, jest przekierowanie standardowego wejścia dla dowolnego polecenia, które w przeciwnym razie mogłoby pochłonąć wejście pętli while.

while read -r LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh "$LINE" </dev/null
done < "$FILENAME"

Dodanie </dev/null jest tutaj kluczowym punktem (choć poprawione cytowanie jest również nieco ważne; ZOBACZ także kiedy owijać cytaty wokół zmiennej powłoki?). Będziesz chciał użyć read -r, chyba że wyraźnie potrzebujesz nieco dziwnego zachowania, które uzyskasz bez -r.

Inny obejście tego rodzaju, które jest nieco specyficzne dla ssh, polega na upewnieniu się, że każde polecenie ssh ma swoje standardowe wejście powiązane, np. poprzez zmianę

ssh otherhost some commands here

Zamiast tego odczytać polecenia z dokumentu here, który wygodnie (dla tego konkretnego scenariusza) wiąże standardowe wejście ssh dla poleceń:

ssh otherhost <<'____HERE'
    some commands here
____HERE
 18
Author: tripleee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-19 08:44:00

Opcja Ssh-N zapobiega sprawdzaniu statusu zakończenia ssh podczas korzystania z HEREdoc podczas przesyłania wyjścia do innego programu. Dlatego preferowane jest użycie /dev / null jako standardowego wejścia.

#!/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
 5
Author: jacobm654321,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-14 22:54:02

Bardzo prostym i solidnym obejściem jest zmiana deskryptora pliku , z którego polecenie read otrzymuje dane wejściowe.

Jest to realizowane przez dwie modyfikacje: argument -u na read i operator przekierowania na < $FILENAME.

W BASH domyślne wartości deskryptora pliku (tj. wartości dla -u w read) to:

  • 0 = stdin
  • 1 = stdout
  • 2 = stderr

Więc po prostu wybierz inny nieużywany deskryptor pliku, tak dla Zabawy.

Oto sposób obejścia problemu:

while read -u 9 LINE; do
   let count++
   echo "$count $LINE"
   sh ./do_work.sh $LINE
done 9< $FILENAME

Zauważ dwie modyfikacje:

  1. read staje się read -u 9
  2. < $FILENAME staje się 9< $FILENAME

Jako najlepsza praktyka robię to dla wszystkich while pętli, które piszę w bashu. Jeśli masz zagnieżdżone pętle za pomocą read, Użyj innego deskryptora pliku dla każdej z nich (9,8,7,...).

 2
Author: cmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-12 21:16:34

Przydarzyło mi się to, ponieważ miałem set -e i grep W pętli wracał bez wyjścia (co daje niezerowy kod błędu).

 1
Author: JonnyRaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-20 06:21:13