O forloop está bom aqui. Mas observe que isso ocorre porque o arquivo contém nomes de máquinas, que não contêm caracteres de espaço em branco ou globbing. for x in $(cat file); do …não funciona para iterar sobre as linhas de fileem geral, porque o shell primeiro divide a saída do comando em cat filequalquer lugar em que haja espaço em branco e, em seguida, trata cada palavra como um padrão glob, para que \[?*sejam expandidas ainda mais. Você pode se for x in $(cat file)proteger se trabalhar nele:
set -f
IFS='
'
for x in $(cat file); do …
Leitura relacionada: Fazendo loop em arquivos com espaços nos nomes? ; Como posso ler linha por linha de uma variável no bash? ; Por que é while IFS= readusado 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 ao que deu errado com sua while readtentativa. O redirecionamento do arquivo da lista de servidores se aplica a todo o loop. Portanto, quando sshexecutado, sua entrada padrão vem desse arquivo. O cliente ssh não pode saber quando o aplicativo remoto pode querer ler de sua entrada padrão. Portanto, assim que o cliente ssh percebe alguma entrada, envia essa entrada para o lado remoto. O servidor ssh então está pronto para alimentar essa entrada para o comando remoto, caso deseje. No seu caso, o comando remoto nunca lê nenhuma entrada; portanto, os dados acabam sendo descartados, mas o lado do cliente não sabe nada sobre isso. Sua tentativa com echofuncionou porque echonunca lê nenhuma entrada, deixa sua entrada padrão em paz.
Existem algumas maneiras de evitar isso. Você pode dizer ao ssh para não ler da entrada padrão, com a -nopção
while read server; do
ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt
A -nopção de fato diz sshpara redirecionar 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 entrada evitar de ssh que vem do arquivo é colocar o redirecionamento no readcomando: while read server </home/kenny/list_of_servers.txt; do …. Isso não funcionará, pois faz com que o arquivo seja aberto novamente toda vez que o readcomando for executado (para ler a primeira linha do arquivo repetidamente). O redirecionamento precisa estar no loop while geral, para que o arquivo seja aberto uma vez durante a duração do loop.
A solução geral é fornecer a entrada para o loop em um descritor de arquivo diferente da entrada padrão. O shell possui 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 readentrada padrão do comando do descritor de arquivo 3. O cliente ssh ignora os descritores não padronizados abertos, para que tudo esteja bem.
while read server <&3; do
ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt
No bash, o readcomando tem uma opção específica para ler de um descritor de arquivo diferente, para que você possa escrever read -u3 server.
Leitura relacionada: Descritores de arquivos e scripts de shell ; Quando você usaria um descritor de arquivo adicional?