2008-12-06 15 views
25

Ho sbattuto la testa contro il muro per un po 'con questo.Bash durante la lettura dell'inizio del ciclo iniziale

Desidero SSH in un set di macchine e verificare se sono disponibili (accettare connessioni e non essere utilizzate). Ho creato un piccolo script, tssh, che fa proprio questo:

#!/bin/bash 

host=$1 
timeout=${2:-1} 

ssh -qo "ConnectTimeout $timeout" $host "[ \`who | cut -f1 | wc -l \` -eq 0 ] && exit 0 || exit 1" 

Questo script funziona correttamente. Restituendo 255 se c'era un problema di connessione, 1 se la macchina è occupata e 0 se tutto è buono. Se qualcuno conosce un modo migliore per farlo, per favore fatemelo sapere.

Quindi dopo provo a chiamare tssh sul mio set di macchine usando un ciclo while read, e questo è dove tutto va storto. Il ciclo termina non appena tssh restituisce 0 e non completa mai il set completo.

while read nu ; do tssh "MYBOXES$nu" ; done < <(ruby -e '(0..20).each { |i| puts i }') 

All'inizio ho pensato che si trattasse di un problema di subshell ma apparentemente no. Qualsiasi aiuto, insieme a commenti su stile/contenuto, sarebbe molto apprezzato! so che sto andando a calci me quando ho scoperto il motivo per cui ...

+0

Sto avendo un problema simile con Net Perl :: :: SSH Perl, @ Foo-Bah ha descritto il problema molto bene, e la soluzione è quella di aggiungere una stringa vuota come parametro al cmd: https://metacpan.org/pod/Net::SSH::Perl#out-err-exit-ssh-cmd-cmd-stdin mio ($ stdout, $ stderr, $ exit) = $ ssh-> cmd ($ cmd, ""); – Thomas

risposta

4

Non so se sarebbe d'aiuto, ma un modo più pulito di scrittura che sarebbe

for nu in `ruby -e '(0..20).each { |i| puts i}'`; do 
    tssh "MYBOXES$nu" 
done 
+3

Inoltre, se si ha GNU Coreutils, è possibile usare 'seq 0 20' invece del comando ruby. –

+0

@Paul Grazie, funziona! Ora se solo sapessi perché! Forse è un problema di subshell dopo tutto. Sicuramente ricorda i precedenti problemi di subshell che ho avuto. @Jouni Ho sostituito la parte brutta di rubino con seq. Non ero a conoscenza di quel comando, grazie. @All Qualche informazione sul perché questa correzione funziona? –

+1

@Paul È un problema ssh. Farò un post –

3

Sono anche incerti circa il motivo per cui non riesce, ma mi piace xargs e seq:

seq 0 20 | xargs -n1 tssh MYBOXES 
2

non posso credere che fosse il risultato di 0 che ha rotto il ciclo, si può confrontare con l'sostituendo il vostro comando tssh nel ciclo con "/bin/true "che restituisce anche 0.

per quanto riguarda lo stile non capisco perché un semplice script di shell di loop abbia bisogno di ruby, perl, seq o jot o qualsiasi altro binario che non sia sul mio * BSD.

in alternativa è possibile utilizzare i gusci integrato per ciclo costrutto, che funziona almeno in ksh, bash:

for ((i=0; $i<=20; i++)); do 
    tssh "MYBOXES$i" 
done 
6

mi sono imbattuto in questo oggi - rsh e/o ssh può rompere un po 'leggere ciclo a causa ad esso usando stdin. Ho inserito un -n nella riga ssh che impedisce di provare a usare stdin e ha risolto il problema.

3

Come diceva Kaii, è davvero eccessivo chiamare ruby ​​o seq (che non funzionerà su macchine BSD o OSX) solo per generare un intervallo di numeri. Se sei felice con l'utilizzo di bash è possibile:

for i in {0..20}; do 
    # command 
done 

Credo che questo dovrebbe funzionare per bash 2.05b in su.

36

Chris è corretto. La fonte della rottura del loop era SSH usando stdin, tuttavia le pistole sono corrette nell'uso di una metodologia di looping.

Se si esegue il looping dell'input (un file con un elenco di nomi host per esempio) e si chiama SSH, è necessario passare il parametro -n, altrimenti il ​​ciclo basato sull'input avrà esito negativo.

while read host; do 
    ssh -n $host "remote command" >> output.txt 
done << host_list_file.txt 
2

parlare di un problema di "rubare Pietro per pagare Paolo". Ho lottato per ore per capire perché il mio ssh stava uccidendo il mio qualcosa mentre leggevo il ciclo.

Un altro modo per attaccare con un ciclo di lettura mentre si mantiene lo ssh allo stesso tempo è usare l'opzione "-n" per rendere STDIN su ssh/dev/null. Funziona come un fascino per me:

#!/bin/bash 
[...] 
something|while read host 
    do 
     ssh -nx ${host} fiddleAround 
    done 

(. Io tendo ad usare sempre il "-x" troppo per evitare di tempo a negoziare X in un tunnel di sprecare)

31

Nel costrutto

something | 
while read x; do 
    ssh ... 
done 

l'ingresso standard visto dal ciclo while è l'uscita di something.

Il comportamento predefinito di ssh è leggere l'input standard. Questo ti permette di fare cose come

cat id_rsa.pub | ssh new_box "cat - >> ~/.ssh/authorized_keys" 

Ora, con questo detto, quando il primo valore viene letto, il primo comando ssh leggerà l'intero input da something. Quindi, al termine della ssh, non viene lasciato alcun output e read si interrompe.

La correzione è ssh -n ... ad es.

cat /etc/hosts | awk '{print $2}' | while read x; do 
    ssh -n $x "do_something_on_the_machine" 
done 
+0

La migliore risposta! – Jer

2

La maggior parte delle risposte sono specifiche per ssh. Anche altri comandi dirottano lo stdin e non hanno un'opzione -n. Questo dovrebbe indirizzare qualsiasi altro comando. Questo dovrebbe funzionare anche per ssh.

while read x; do 
    # Make sure command does not hijack stdin 
    echo "" | command $x 
done < /path/to/some/file 
Problemi correlati