
Suponha que eu queira me conectar à máquina B por meio da máquina A. Como aprendi, existem várias maneiras de fazer isso, por exemplo
ssh -T -J user@machineA user@machineB << END_OF_SSH_CONNECTION
# Some commands in machine B
END_OF_SSH_CONNECTION
ou
ssh -T user@machineA << END_OF_MACHINE_A
ssh -T machine B << END_OF_MACHINE_B
# Some commands in machine B
END_OF_MACHINE_B
END_OF_MACHINE_A
No entanto, não está claro para mim como iniciar um shell interativo onde o usuário possa digitar comandos quando conectado à máquina B. Por exemplo, isso funciona:
ssh user@machineA -t 'bash -l -c "bash"'
e isso também funciona:
ssh -J user@machineA user@machineB -t 'bash -l -c "bash"'
O seguinte não funciona, no entanto:
ssh -J user@machineA user@machineB -t 'sudo apt-get update; bash -l -c "bash"'
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Connection to machineB closed.
E nem o seguinte:
ssh -J user@machineA user@machineB -t 'if [ 1 -eq 1 ]; then bash -l -c "bash"; fi'
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Connection to machineB closed.
Eu também tentei isso:
ssh -T -J user@machineA user@machineB << EOF
# Some commands on machineB
# Check whether apache2 has been correctly installed
if [ $(dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -c "ok installed") -eq 1 ];
then
printf "done\n";
else
printf "fail\nStarting an interactive shell: enter exit to quit\n";
bash -l -c "bash";
fi
EOF
Esta última versão quase funciona (ou seja, não retorna erros), mas não inicia um shell interativo onde o usuário pode digitar comandos como seria de esperar.
Espero que alguém possa me ajudar. Desde já, obrigado.
Responder1
Obrigado pela ajuda, @attie. Modifiquei um pouco seu código proposto, que relato aqui abaixo
#!/usr/bin/env bash ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF" if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then echo "done"; else echo "fail, starting an interactive shell"; bash -l -c "bash"; fi EOF ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
nisso, que nem precisa gravar em um arquivo externo.
#!/usr/bin/env bash
ssh -T -J user@machineA user@machineB << "EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q "ok installed"; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
Basicamente, eu estava sentindo falta das aspas EOF
, usadas para evitar uma tentativa de expansão do campo ${Status}
.
Responder2
Se você deseja executar um script no host remotoeobter um shell interativo, você terá duas opções:
- Coloque todo o script nos argumentos da linha de comando para
ssh
. - Envie o script para o host remoto (por exemplo: usando
scp
oussh
) e execute-o (por exemplo: usandossh
)
1. Script em Args
Seu último exemplo está à beira de "longo" para esta abordagem, mas você pode ajudar na legibilidade usandomapfile
(um embutido bash
). Observe o citado "EOF"
para evitar uma tentativa de expansão ${Status}
.
mapfile -t SCRIPT <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "${SCRIPT[@]}"
2. Envie o script e execute
Pontos de bônus por usar mktemp
e limpar depois. Nota citada "EOF"
novamente.
Com base em uma das mensagens de erro fornecidas (em torno de exec
, veja abaixo para mais informações), esse uso cat >/tmp/myscript
provavelmente não funcionará.
ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
echo "done";
else
echo "fail, starting an interactive shell";
bash -l -c "bash";
fi
EOF
ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"
O primeiro passo deve ser sempre tentar dividir o problema na forma mais simples... Quanto ao seu último encantamento, tente o seguinte:
ssh -T user@machineA << EOF
bash -l -c "bash";
EOF
O que acontece? Você receberá mensagens de boas-vindas do host remoto, mas a sessão terminará imediatamente e silenciosamente, sem erros.
Alterar -T
(explicitamentedesabilitarAlocação de PTY) para -t
(forçar alocação de PTY) fornece uma dica na direção certa:
ssh -t user@machineA << EOF
bash -l -c "bash";
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.
Isso indica que você está usando stdin
para fornecer um script e também tentando conectá-lo stdin
(um canal, não um terminal) ao PTY remoto.
Então vamos remover o stdin
fator:
ssh -t user@machineA bash -l -c "bash"
E funciona!
Fundamentalmente vocênão podecompartilhe stdin com um script e um terminal.
Quanto aos outros erros:
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Novamente, analise-o para encontrar o problema. Infelizmente esses comandos funcionam para mim, suspeito porque os sistemas aos quais tenho acesso estão usando sh -c "${ARGS}"
ou similares. No entanto, outro erro que você forneceu dá uma dica:
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Parece que seu sistema está usando exec
para executar o comando fornecido como argumento para ssh
... o que significa que o shell não é capaz de lidar com coisas como if
ou ;
para você como você espera - então if
não é um binário no caminho e falha .
Da mesma forma, todos os argumentos são dados de sudo
uma só vez:
sudo
apt-get
update;
bash
-l
-c
"bash"
Com certeza, o argumento sudo
de -l
(lista) é mutuamente exclusivo com -c
(classe de login).