O loop for
está bem aqui. Mas note que isso ocorre porque o arquivo contém nomes de máquina, que não contêm caracteres de espaço em branco ou caracteres globbing. for x in $(cat file); do …
não funciona para iterar as linhas de file
em geral, porque o shell primeiro divide a saída do comando cat file
em qualquer lugar onde houver espaço em branco e, em seguida, trata cada palavra como um padrão de glob assim \[?*
expandido ainda mais. Você pode tornar for x in $(cat file)
seguro se você trabalhar nele:
set -f
IFS='
'
for x in $(cat file); do …
Leitura relacionada: Percorrendo arquivos com espaços nos nomes ? ; Como posso ler a linha por linha de uma variável no bash? ; Por que é while IFS= read
usado com tanta frequência, em vez de IFS=; while read..
? Observe que ao usar while read
, a sintaxe segura para ler linhas é while IFS= read -r line; do …
.
Agora vamos ver o que há de errado com sua tentativa while read
. O redirecionamento do arquivo de lista de servidores se aplica ao loop inteiro. Então, quando ssh
é executado, sua entrada padrão vem desse arquivo. O cliente ssh não pode saber quando o aplicativo remoto pode querer ler sua entrada padrão. Então, assim que o cliente ssh percebe alguma entrada, ele envia essa entrada para o lado remoto. O servidor ssh está pronto para alimentar essa entrada para o comando remoto, caso ele queira. No seu caso, o comando remoto nunca lê nenhuma entrada, então os dados acabam sendo descartados, mas o lado do cliente não sabe nada sobre isso. Sua tentativa com echo
funcionou porque echo
nunca lê nenhuma entrada, ela deixa sua entrada padrão sozinha.
Existem algumas maneiras de evitar isso. Você pode dizer ao ssh para não ler a entrada padrão, com a opção -n
.
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
A opção -n
diz, de fato, que ssh
redireciona sua entrada de /dev/null
. Você pode fazer isso no nível do shell e funcionará para qualquer comando.
while read server; do
ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt
Um método tentador para evitar a entrada de ssh proveniente do arquivo é colocar o redirecionamento no comando read
: while read server </home/kenny/list_of_servers.txt; do …
. Isso não funcionará, porque faz com que o arquivo seja aberto novamente toda vez que o comando read
for executado (para que ele leia a primeira linha do arquivo várias vezes). O redirecionamento precisa estar em todo o loop while para que o arquivo seja aberto uma vez pela duração do loop.
A solução geral é fornecer a entrada para o loop em um descritor de arquivo além da entrada padrão. O shell tem construções para transportar entrada e saída de um número de descritor para outro. Aqui, abrimos o arquivo no descritor de arquivo 3 e redirecionamos a entrada padrão do comando read
do descritor de arquivo 3. O cliente ssh ignora os descritores não-padrão abertos, portanto, tudo está bem.
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
No bash, o comando read
tem uma opção específica para ler um descritor de arquivo diferente, portanto você pode escrever read -u3 server
.
Leitura relacionada: Descritores de arquivos & script de shell ; Quando você usaria um descritor de arquivo adicional?