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ń.
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.
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
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
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:
-
read
staje sięread -u 9
-
< $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,...).
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).
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