Estou tentando executar um comando em uma série de servidores via ssh. Recentemente mudei as portas ssh para evitar scanners de Internet, mas isso quebrou meu script. Alguém conhece "uma maneira fácil" de especificar portas diferentes por entrada usuário@servidor em um loop for?
for i in '[email protected] -p 12345' '[email protected] -p 54321'
do printf "\e[%sm%s\e[00m\n" 32 $i
ssh $i crontab -l
done
A segunda linha serve apenas para imprimir o nome do servidor antes da saída (para facilitar a leitura).
Em vez de felicidade me deu:ssh: Could not resolve hostname server1.domain1.com -p 12345: Name or service not known
Funcionou antes, quando todas as portas eram o padrão 22 e não precisavam ser especificadas.
Versões recentes do OpenSSH
ssh
( desde v7.7 ) (junto com seuscp
esftp
) aceitarão o destino na forma de um URI. Você pode especificar o número da porta como parte do URI se desejar, por exemplo "ssh://someuser@somehost:42" para conectar-se à porta 42. Um URI tem a vantagem de ser uma única string, no que diz respeito ao shell está preocupado. Então você pode fazer isso:A forma geral de um URI SSH é "ssh://user@host:port". As partes "usuário" e "porta" são opcionais e podem ser omitidas (junto com a pontuação "@" ou ":") se você não precisar especificar valores para elas.
A maneira correta seria armazenar isso na configuração, em vez de especificar tudo em cada conexão.
Em
~/.ssh/config
você poderia ter:Então
ssh server1.domain1.com
eussh serv2
faria a coisa certa™. Não há necessidade de lembrar os nomes de usuário ou a porta usada para cada máquina. Beneficiando scripts e humanos.E se você alterar as portas posteriormente, há um único local para modificar.
Também é possível usar curingas, portanto, se todas as máquinas
domain1.com
tivessem seu sshd escutando na porta 1234, você poderia combinar todas elas comHost *.domain1.com
, sem precisar listá-las individualmente.Para um
for
loop que pode percorrer mais de uma variável, mude parazsh
. Você já está usandozsh
sintaxe ao não citar suas variáveis:Para percorrer listas de argumentos, você pode usar um shell com matrizes multidimensionais, como
ksh93
:Ou faça com que os elementos do array contendo strings com os argumentos sejam concatenados usando um caractere que você sabe que não ocorre nas strings e divida-os.
zsh
tem um${(s[x])var}
caráter de divisão.ksh e bash também fazem isso, mas é apenas por meio do desajeitado split + glob que é invocado implicitamente quando você se esquece de citar uma expansão lá. Você poderia usá-lo como:
Isso é basicamente o que você fez em sua abordagem, exceto que usou espaço em vez de
:
para separar os elementos, mas não definiu$IFS
e não desativou o glob.O fato de você
$i
não ter sido dividido pode ser explicado por$IFS
ser definido como uma string vazia ou pelo código executado por zsh em vez de bash, onde nem a divisão nem o globbing são feitos implicitamente na expansão dos parâmetros.No zsh, se você quiser a divisão IFS, use
$=var
em vez de$var
, e se quiser globbing:$~var
. bash$var
é como zsh$=~var
. Então, no zsh, você precisaria de:Uma abordagem portátil que funcionaria
sh
seria escrevê-la:Omitir a
-r
opçãoread
permite que os valores contenham o separador (aqui espaço) prefixando-os com uma barra invertida como em:Mas, ao contrário das outras abordagens, não permite que esses valores contenham caracteres de nova linha (provavelmente não é um problema para usuários, hosts, nomes de serviços ou números de portas).
Outro método portátil para fazer um loop em listas que possuem o mesmo
$n
número de elementos e que não têm essa limitação é armazenar todos os elementos nos parâmetros posicionais e fazer um loop sobre eles em umwhile [ "$#" -ge "$n" ]; do something with "$1" "$2"...; shift "$n"; done
loop. Então aqui:Uma solução geral para percorrer duas listas, usando um par de elementos (um de cada lista) em cada iteração do loop, em um shell POSIX:
Use pdsh para vários hosts. É amplamente utilizado em data centers com grande número de hosts em cluster.
Da documentação do pdsh ..
https://code.google.com/archive/p/pdsh/wikis/UsingPDSH.wiki
Esta ferramenta junto com o arquivo de configuração ssh como Ángel mencionou.
Exemplo completo abaixo..
~/.ssh/config
Agora corrida simples