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 while
y 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 while
ciclo 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 for
bucle 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
ansible
Respuestas:
ssh
está leyendo el resto de su entrada estándar.read
lee 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
cat
comió (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é
for
funciona?Su
for
línea no redirige a stdin. (De hecho, lee todo el contenido delservers.txt
archivo en la memoria antes de la primera iteración). Entoncesssh
continú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
read
usado un descriptor de archivo diferente.Debería funcionar.
10
es 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
-n
opció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
10
viene 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.-u
opción no es compatible con POSIX, y por lo tanto no debe ser utilizado para#!/bin/sh
las secuencias de comandos; utilizarread HOST <&10
en su lugar. Además, POSIX solo requiere shells para admitir los descriptores de archivo 0 a 9, por10<servers.txt
lo que no se puede usar si el script debe cumplir estrictamente.Como describe derobert
ssh
lee 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 .
-i
significa 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 fabric
Cree un archivo
fabfile.py
con el siguiente código:Luego ejecutar
fab mytask
le dará el resultado que desea.fuente
Es más fácil usar un comando como este:
Por lo general, me gusta esto:
El
echo
es 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