tutorial script comandos bourne again bash shell

script - Bash while read loop breaking early



bourne again shell (9)

No sé si sería útil, pero una forma más limpia de escribir sería

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

He estado golpeando mi cabeza contra la pared por un tiempo con esta.

Quiero SSH en un conjunto de máquinas y verificar si están disponibles (aceptar conexiones y no usarlas). He creado un pequeño script, tssh, que hace precisamente eso:

#!/bin/bash host=$1 timeout=${2:-1} ssh -qo "ConnectTimeout $timeout" $host "[ /`who | cut -f1 | wc -l /` -eq 0 ] && exit 0 || exit 1"

Esta secuencia de comandos funciona correctamente. Devolviendo 255 si hubo un problema de conexión, 1 si la máquina está ocupada y 0 si todo está bien. Si alguien conoce una mejor manera de hacerlo, por favor avíseme.

Entonces, probé y llamé a tssh en mi conjunto de máquinas usando un ciclo while read, y aquí es donde todo sale mal. El ciclo se cierra tan pronto como tssh regrese a 0 y nunca complete el conjunto completo.

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

Al principio pensé que esto era un problema de subshell pero aparentemente no. ¡Cualquier ayuda, junto con comentarios sobre el estilo / contenido, sería muy apreciada! Sé que voy a patearme cuando descubra por qué ...


Tampoco estoy seguro de por qué falla, pero me gusta xargs y seq :

seq 0 20 | xargs -n1 tssh MYBOXES


no puedo creer que fue el resultado de 0 que rompió su ciclo, puede probarlo al reemplazar su comando tssh en el ciclo con "/ bin / true" que también devuelve 0.

con respecto al estilo, no entiendo por qué una secuencia de comandos de shell con bucle simple necesita ruby, perl, seq o jot o cualquier otro binario que no esté en mi * BSD.

alternativamente puede usar las conchas incorporadas para la construcción de bucles, que funciona al menos en ksh, bash:

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


Me encontré con esto hoy - rsh y / o ssh pueden romper un ciclo de lectura debido a que usa stdin. Puse una -n en la línea ssh que evita que intente usar stdin y solucionó el problema.


Chris es correcto. La fuente del rompimiento del bucle fue SSH usando stdin, sin embargo, las armas son correctas en el uso de una metodología de bucle.

Si realiza un bucle a través de la entrada (un archivo con una lista de nombres de host, por ejemplo) y llama a SSH, debe pasar el parámetro -n; de lo contrario, su bucle basado en la entrada fallará.

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


Como mencionó Kaii, es realmente excesivo llamar a ruby ​​o seq (que no funcionará en máquinas BSD u OSX) solo para generar un rango de números. Si estás contento con el uso de bash, puedes:

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

Creo que esto debería funcionar para bash 2.05bo en adelante.


En la construcción

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

la entrada estándar vista por el ciclo while es la salida de something .

El comportamiento predeterminado de ssh es leer la entrada estándar. Esto te permite hacer cosas como

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

Ahora, dicho esto, cuando se lee el primer valor, el primer comando ssh leerá la entrada completa de something . Luego, cuando termina ssh, no queda salida, y la read detiene.

La solución es ssh -n ... por ejemplo

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


hablar sobre un problema de "robar a Peter para pagarle a Paul". Había estado luchando durante horas para descubrir por qué mi ssh estaba matando mi algo | while read loop.

Otra forma de seguir con un ciclo de lectura while y mantener su ssh al mismo tiempo es usar el interruptor "-n" para hacer que STDIN esté en ssh / dev / null. Funciona como un encanto para mí:

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

(Tiendo a usar siempre el "-x" también para evitar perder el tiempo negociando X en un túnel).


La mayoría de las respuestas son específicas de ssh. Otros comandos también secuestran stdin y no tienen una opción -n. Esto debería abordar cualquier otro comando. Esto también debería funcionar para ssh.

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