Estou tentando reiniciar vários servidores Ubuntu via script quando uma reinicialização é necessária.
Quando executo o bash com o teste como um comando não interativo, obtenho o resultado de que nenhuma reinicialização é necessária, mesmo que o arquivo /var/run/reboot-required
exista.
usera@client:~$ ssh server02 bash -c 'test -f /var/run/reboot-required && echo sudo reboot || echo "$(hostname): no reboot required"'
server02: no reboot required
Quando entro no mesmo servidor via SSH e executo meu teste manualmente recebo o resultado correto, sudo reboot
.
usera@client:~$ ssh server02
Last login: Tue Jun 14 08:03:00 2022 from 146.140.16.1
usera@server02:~$ test -f /var/run/reboot-required && echo sudo reboot || echo "$(hostname): no reboot required"
sudo reboot
usera@server02:~$ bash -c 'test -f /var/run/reboot-required && echo sudo reboot || echo "$(hostname): no reboot required"'
sudo reboot
O que preciso mudar para obter o resultado correto?
Tenho certeza de que é por causa da maneira como o SSH passa uma linha de comando para a extremidade remota e faz isso concatenando todos os argumentos que obtém, juntando-os com espaços e deixando o shell no remoto analisar e executar isso.
Considere, por exemplo, que
ssh somehost ls -l /etc/passwd
funciona da mesma forma quessh somehost 'ls -l /etc/passwd'
, o último não fornece um erro sobre um comando com nome estranho não existir, ao contrário de se você apenas executar'ls -l /etc/passwd'
diretamente em uma linha de comando do shell.Então,
se transforma na linha de comando
onde Bash executa o comando
test
, com$0
definido comowhatever
.test
sem argumentos falha, então as|| echo
corridas. Você pode tentar algo comossh somehost bash -c 'ls -l /etc/passwd'
também, ele deve ser executadols
em seu diretório inicial remoto.Então, tente sem o shell intermediário:
ou você poderia fazer algo como
mas a citação fica nojenta se você quiser aninhar outra string entre aspas e certificar-se de que é o shell mais interno que executa todas as expansões que você possui. Não importa muito
$(hostname)
, pois dará o mesmo resultado de qualquer shell no controle remoto, mas em um caso mais geral, o inferno das citações está lá. Em casos complexos como esse, seria muito mais fácil criar um arquivo no controle remoto e executar o script a partir daí.Este é basicamente o mesmo problema do comando ssh com aspas .
Veja também Executando o script `sh -c` através do SSH (passando argumentos com segurança e sensatez) para outras soluções para passar comandos complexos, e Como executar um comando simples arbitrário sobre ssh sem conhecer o shell de login do usuário remoto? para o caso mais raro envolvendo um shell de login remoto possivelmente desconhecido.