GNU/Linux >> Linux Esercitazione >  >> Linux

Lettura di righe da un file con Bash:per vs. Mentre?

Sto cercando di leggere un file di testo e fare qualcosa con ogni riga, usando uno script bash.

Quindi, ho un elenco simile a questo:

server1
server2
server3
server4

Ho pensato di poter ripetere questo ciclo usando un ciclo while, in questo modo:

while read server; do
  ssh $server "uname -a"
done < /home/kenny/list_of_servers.txt

Il ciclo while si interrompe dopo 1 esecuzione, quindi eseguendo solo uname -a sul server1

Tuttavia, con un ciclo for che usa cat funziona bene:

for server in $(cat /home/kenny/list_of_servers.txt) ; do
  ssh $server "uname -a"
done

Ancora più sconcertante per me è che funziona anche questo:

while read server; do
  echo $server
done < /home/kenny/list_of_servers.txt

Perché il mio primo esempio si interrompe dopo la prima iterazione?

Risposta accettata:

Il for il ciclo va bene qui. Ma nota che ciò è dovuto al fatto che il file contiene nomi di macchine, che non contengono caratteri di spazi vuoti o caratteri di globbing. for x in $(cat file); do … non funziona per scorrere le righe di file in generale, perché la shell prima divide l'output dal comando cat file ovunque ci sia uno spazio bianco, quindi tratta ogni parola come un pattern glob quindi \[?* vengono ulteriormente ampliati. Puoi creare for x in $(cat file) sicuro se ci lavori:

set -f
IFS='
'
for x in $(cat file); do …

Lettura correlata:scorrere i file con spazi nei nomi?; Come posso leggere riga per riga da una variabile in bash?; Perché while IFS= read usato così spesso, invece di IFS=; while read.. ? Nota che quando usi while read , la sintassi sicura per leggere le righe è while IFS= read -r line; do … .

Ora passiamo a cosa non va con il tuo while read tentativo. Il reindirizzamento dal file di elenco dei server si applica all'intero ciclo. Quindi quando ssh viene eseguito, il suo input standard proviene da quel file. Il client ssh non può sapere quando l'applicazione remota potrebbe voler leggere dal suo input standard. Quindi, non appena il client ssh nota un input, invia quell'input al lato remoto. Il server ssh è quindi pronto per inviare quell'input al comando remoto, se lo desidera. Nel tuo caso, il comando remoto non legge mai alcun input, quindi i dati finiscono per essere scartati, ma il lato client non ne sa nulla. Il tuo tentativo con echo ha funzionato perché echo non legge mai alcun input, lascia solo il suo input standard.

Ci sono alcuni modi per evitarlo. Puoi dire a ssh di non leggere dallo standard input, con -n opzione.

while read server; do
  ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt

Il -n l'opzione infatti dice a ssh per reindirizzare il suo input da /dev/null . Puoi farlo a livello di shell e funzionerà per qualsiasi comando.

while read server; do
  ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt

Un metodo allettante per evitare l'input di ssh proveniente dal file è inserire il reindirizzamento su read comando:while read server </home/kenny/list_of_servers.txt; do … . Questo non funzionerà, perché fa sì che il file venga aperto di nuovo ogni volta che read il comando viene eseguito (quindi leggerebbe la prima riga del file più e più volte). Il reindirizzamento deve essere sull'intero ciclo while in modo che il file venga aperto una volta per la durata del ciclo.

Correlati:BashScript funziona da Terminal ma non da CronTab?

La soluzione generale consiste nel fornire l'input al ciclo su un descrittore di file diverso dallo standard input. La shell ha costrutti per trasferire input e output da un numero di descrittore a un altro. Qui, apriamo il file sul descrittore di file 3 e reindirizziamo il read input standard del comando dal descrittore di file 3. Il client ssh ignora i descrittori non standard aperti, quindi va tutto bene.

while read server <&3; do
  ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt

In bash, il read comando ha un'opzione specifica per leggere da un descrittore di file diverso, quindi puoi scrivere read -u3 server .

Lettura correlata:Descrittori di file e script di shell; Quando useresti un descrittore di file aggiuntivo?


Linux
  1. È possibile in Bash iniziare a leggere un file da un offset arbitrario del conteggio dei byte?

  2. Leggere i modelli Grep da un file?

  3. Esempi di Bash For Loop e While Loop

  4. Lettura da un file in assembly

  5. Aggiunta di timestamp a un nome file con mv in BASH

Come leggere i file riga per riga in Bash

Come leggere un file riga per riga in Bash

Bash For Loop con esempi pratici

Reindirizzamento Bash spiegato con esempi

Scripting Bash:come leggere i dati dai file di testo

Bash Scripting Part2 – Cicli For e While con esempi