Eu tenho um arquivo servers.txt
, com lista de servidores:
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com
quando leio o arquivo linha por linha com while
e ecoo cada linha, tudo funciona conforme o esperado. Todas as linhas são impressas.
$ while read HOST ; do echo $HOST ; done < servers.txt
server1.mydomain.com
server2.mydomain.com
server3.mydomain.com
No entanto, quando eu quero ssh para todos os servidores e executar um comando, de repente meu while
loop para 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
Isso se conecta apenas ao primeiro servidor da lista, não a todos eles. Eu não entendo o que está acontecendo aqui. Alguém pode me explicar?
Isso é ainda mais estranho, pois o uso de for
loop funciona bem:
$ 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
Deve ser algo específico ssh
, porque outros comandos funcionam bem, como ping
:
$ while read HOST ; do ping -c 1 $HOST ; done < servers.txt
ssh
scripting
io-redirection
Martin Vegter
fonte
fonte
ansible
Respostas:
ssh
está lendo o restante de sua entrada padrão.read
lê de stdin. O<
redireciona stdin de um arquivo.Infelizmente, o comando que você está tentando executar também lê stdin, e acaba consumindo o restante do seu arquivo. Você pode ver claramente com:
Observe como
cat
comeu (e ecoou) as duas linhas restantes. (Se o tivesse lido conforme o esperado, cada linha teria o "início" e o "fim" em torno do host.)Por que
for
funciona?Sua
for
linha não redireciona para stdin. (De fato, ele lê todo o conteúdo doservers.txt
arquivo na memória antes da primeira iteração). Então,ssh
continua a ler seu stdin no terminal (ou possivelmente nada, dependendo de como seu script é chamado).Solução
Pelo menos no bash, você pode
read
usar um descritor de arquivo diferente.deveria funcionar.
10
é apenas um número de arquivo arbitrário que eu escolhi. 0, 1 e 2 definiram significados e, normalmente, a abertura de arquivos será iniciada a partir do primeiro número disponível (então será o próximo a ser usado 3). 10 é alto o suficiente para ficar fora do caminho, mas baixo o suficiente para ficar abaixo do limite em algumas conchas. Além disso, é um bom número redondo ...Solução alternativa 1: -n
Como McNisse aponta em sua resposta , o cliente OpenSSH tem uma
-n
opção que impede que ele leia stdin. Isso funciona bem no caso particular dessh
, mas é claro que outros comandos podem não ter isso - as outras soluções funcionam independentemente de qual comando está consumindo seu stdin.Solução alternativa 2: segundo redirecionamento
Você pode aparentemente (como eu tentei, funciona na minha versão do Bash pelo menos ...) fazer um segundo redirecionamento, que se parece com isso:
Você pode usar isso com qualquer comando, mas será difícil se você realmente quiser que a entrada do terminal vá para o comando.
fonte
10
?exec 3<&0; while read HOST; do ssh $HOST "uname -a" <&3; done <servers.txt; exec 3<&-
isso torna o descritor de arquivo 3 um backup do stdin original, depois o usa para o stdin do ssh e, em seguida, fecha o FD do backup quando concluído. Isso funciona em qualquer shell compatível com POSIX.-u
opção não é suportada pelo POSIX e, portanto, não deve ser usada para#!/bin/sh
scripts; use emread HOST <&10
vez disso. Além disso, o POSIX requer apenas shells para dar suporte aos descritores de arquivos de 0 a 9, portanto,10<servers.txt
não pode ser usado se o script estiver em conformidade estrita.Como derobert descreve
ssh
lê o seustdin
.Para alterar esse comportamento, você pode adicionar -n no ssh para impedir que ele leia stdin.
fonte
Você provavelmente seria melhor usar o pssh do projeto paralelo-ssh .
-i
significa interativo. O pssh também vem com um scp e um rsync paralelos. O interessante é que ele é executado de forma assíncrona e executa quantos threads você solicita. O padrão (não -i / interativo) é produzir em diretórios separados para stdout / stderr, o que é feito por $ outputdir / $ hostname.fonte
Se você se encontra fazendo esse tipo de tarefa com bastante frequência, tente o Fabric
Instale o Fabric seguindo as instruções , na maioria dos casos, você só precisa
sudo apt-get install fabric
Crie um arquivo nomeado
fabfile.py
com o seguinte código:Em seguida, execute
fab mytask
o resultado desejado.fonte
É mais fácil usar um comando como este:
Eu costumo fazer assim:
O
echo
é para ver qual servidor está bloqueado ou não pode se conectar a ele.fonte
Como um commn ssh obtém todo o fluxo da entrada padrão, alimentada pela instrução while,
Você pode usar um pipe para alternar o stdin do ssh para outra fonte:
exemplo:
A entrada stdin de todos os comandos ssh em um loop while deve ser alternada para outra fonte.
fonte