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
Esta pregunta ya tiene una respuesta aquí:
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