Lo script della shell durante la lettura del ciclo di riga si interrompe dopo la prima riga


107

Ho il seguente script di shell. Lo scopo è di eseguire il ciclo attraverso ogni riga del file di destinazione (il cui percorso è il parametro di input dello script) e lavorare su ogni riga. Ora, sembra funzionare solo con la primissima riga nel file di destinazione e si ferma dopo che quella riga è stata elaborata. C'è qualcosa di sbagliato nel mio script?

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

In do_work.sh, eseguo un paio di sshcomandi.


1
Il tuo script va bene, ma potrebbe esserci qualcosa di sbagliato in do_work.sh
sleepsort

2
Sì, potrebbe consumare tutto l'input, oppure potrebbe essere invocato come sourcee semplicemente uscire o exec. Ma questo codice non sembra autentico, l'OP -e
noterebbe

3
Non do_work.shgestito sshper caso?
dogbane

1
sì, do_work.sh esegue un paio di comandi ssh. qualcosa di speciale in questo?
bcbishop

1
Meglio che mostri la do_work.shfonte e corri anche do.shcon il set -xdebug.
koola

Risposte:


178

Il problema è che do_work.shesegue i sshcomandi e per impostazione predefinita sshlegge da stdin che è il tuo file di input. Di conseguenza, viene visualizzata solo la prima riga elaborata, poiché sshconsuma il resto del file e il ciclo while termina.

Per evitare ciò, passa l' -nopzione al tuo sshcomando per farlo leggere da /dev/nullinvece che da stdin.


1
Molto utile, mi ha aiutato a eseguire questo zsh oneliner: cat hosts | durante la lettura host; fare ssh $ host fare_qualcosa; fatto
ratto

3
@rat Vuoi comunque evitare l' inutile cat. Penseresti che un roditore in particolare sarebbe diffidente nei confronti di questo.
tripleee

while read host ; do $host do_something ; done < /etc/hostslo eviterei. È un bel risparmiatore di vita, grazie!
ratto

httpieè un altro comando che legge STDIN per impostazione predefinita e subirà lo stesso comportamento quando viene chiamato all'interno di un bash o di un fish loop. Utilizzare http --ignore-stdino impostare lo standard input /dev/nullcome sopra.
Raman

12

Più in generale, una soluzione alternativa che non è specifica sshè reindirizzare l'input standard per qualsiasi comando che altrimenti potrebbe consumare l' whileinput del ciclo.

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

L'aggiunta di </dev/nullè il punto cruciale qui (sebbene anche le virgolette corrette siano piuttosto importanti; vedere anche Quando avvolgere le virgolette attorno a una variabile di shell? ). Ti consigliamo di utilizzare a read -rmeno che tu non richieda specificamente il comportamento leggermente strano dell'eredità di cui fai a meno -r.

Un'altra soluzione alternativa è in qualche modo specifica per sshassicurarsi che ogni sshcomando abbia il suo input standard vincolato, ad es. Cambiando

ssh otherhost some commands here

leggere invece i comandi da un here document, che convenientemente (per questo particolare scenario) lega lo standard input di sshper i comandi:

ssh otherhost <<'____HERE'
    some commands here
____HERE

5

L'opzione ssh -n impedisce di controllare lo stato di uscita di ssh quando si usa HEREdoc mentre si invia l'output a un altro programma. Quindi l'uso di / dev / null come stdin è preferito.

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

Questo non ha senso. Il <<EOFsovrascrive il </dev/nullreindirizzamento. Il <<reindirizzamento dopo il file doneè sbagliato.
tripleee

1

Questo mi stava accadendo perché avevo set -ee un grepin un ciclo stava tornando senza output (che fornisce un codice di errore diverso da zero).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.