Tengo un archivo servers.txt, con una lista de servidores:
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com
cuando leo el archivo línea por línea con whiley hago eco de cada línea, todo funciona como se esperaba. Todas las líneas están impresas.
$ while read HOST ; do echo $HOST ; done < servers.txt
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com
Sin embargo, cuando quiero ssh a todos los servidores y ejecutar un comando, de repente mi whileciclo deja de funcionar:
$ while read HOST ; do ssh $HOST "uname -a" ; done < servers.txt
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Esto solo se conecta al primer servidor de la lista, no a todos. No entiendo lo que está pasando aquí. ¿Alguien puede explicar?
Esto es aún más extraño, ya que usar el forbucle funciona bien:
$ for HOST in $(cat servers.txt ) ; do ssh $HOST "uname -a" ; done
Linux server1 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server2 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Linux server3 2.6.30.4-1 #1 SMP Wed Aug 12 19:55:12 EDT 2009 i686 GNU/Linux
Debe ser algo específico para ssh, porque otros comandos funcionan bien, como ping:
$ while read HOST ; do ping -c 1 $HOST ; done < servers.txt
ssh
scripting
io-redirection
Martin Vegter
fuente
fuente

ansibleRespuestas:
sshestá leyendo el resto de su entrada estándar.readlee de stdin. El<redireccionamiento stdin desde un archivo.Desafortunadamente, el comando que está intentando ejecutar también lee stdin, por lo que termina comiendo el resto de su archivo. Puedes verlo claramente con:
Observe cómo
catcomió (y repitió) las dos líneas restantes. (Si lo hubiera leído como se esperaba, cada línea tendría el "inicio" y el "final" alrededor del host).¿Por qué
forfunciona?Su
forlínea no redirige a stdin. (De hecho, lee todo el contenido delservers.txtarchivo en la memoria antes de la primera iteración). Entoncessshcontinúa leyendo su stdin desde la terminal (o posiblemente nada, dependiendo de cómo se llame su script).Solución
Al menos en bash, puede haber
readusado un descriptor de archivo diferente.Debería funcionar.
10es solo un número de archivo arbitrario que elegí. 0, 1 y 2 tienen significados definidos y, por lo general, la apertura de archivos comenzará desde el primer número disponible (por lo tanto, 3 será el siguiente). Por lo tanto, 10 es lo suficientemente alto como para mantenerse alejado, pero lo suficientemente bajo como para estar por debajo del límite en algunos proyectiles. Además es un buen número redondo ...Solución alternativa 1: -n
Como McNisse señala en su respuesta , el cliente OpenSSH tiene una
-nopción que le impedirá leer stdin. Esto funciona bien en el caso particular dessh, pero, por supuesto, otros comandos pueden carecer de esto; las otras soluciones funcionan independientemente de qué comando se está comiendo su stdin.Solución alternativa 2: segunda redirección
Aparentemente puede (como en, lo probé, funciona en mi versión de Bash al menos ...) hacer una segunda redirección, que se parece a esto:
Puede usar esto con cualquier comando, pero será difícil si realmente desea que la entrada del terminal vaya al comando.
fuente
10viene el número ?exec 3<&0; while read HOST; do ssh $HOST "uname -a" <&3; done <servers.txt; exec 3<&-Esto hace que el descriptor de archivos 3 sea una copia de seguridad del stdin original, luego lo usa para el stdin de ssh, luego cierra el FD de respaldo cuando haya terminado. Esto funciona en cualquier shell compatible con POSIX.-uopción no es compatible con POSIX, y por lo tanto no debe ser utilizado para#!/bin/shlas secuencias de comandos; utilizarread HOST <&10en su lugar. Además, POSIX solo requiere shells para admitir los descriptores de archivo 0 a 9, por10<servers.txtlo que no se puede usar si el script debe cumplir estrictamente.Como describe derobert
sshlee tustdin.Para cambiar este comportamiento, puede agregar -n no ssh para evitar que lea stdin.
fuente
Probablemente sea mejor usar pssh del proyecto parallel-ssh .
-isignifica interactivo. pssh también viene con un scp paralelo y rsync paralelo. Lo bueno es que se ejecuta de forma asíncrona y ejecutará tantos subprocesos como usted lo solicite. El valor predeterminado (no i / interactivo) es enviar a directorios separados para stdout / stderr, lo que hace por $ outputdir / $ hostname.fuente
Si te encuentras haciendo este tipo de tarea con bastante frecuencia, deberías probar Fabric
Instale el Fabric siguiendo las instrucciones , la mayoría de los casos solo necesita
sudo apt-get install fabricCree un archivo
fabfile.pycon el siguiente código:Luego ejecutar
fab mytaskle dará el resultado que desea.fuente
Es más fácil usar un comando como este:
Por lo general, me gusta esto:
El
echoes ver qué servidor está atascado, o no puede conectarse a él.fuente
Debido a que un comando ssh y toma todo el flujo de la entrada estándar, alimentado por la instrucción while,
Puede usar una tubería para cambiar el stdin de ssh a otra fuente:
ejemplo:
La entrada estándar de todos los comandos ssh en un ciclo while debe cambiarse a otra fuente.
fuente