
Supongamos que quiero conectarme a la máquina B a través de la máquina A. Como aprendí, hay varias formas de lograr esto, por ejemplo
ssh -T -J user@machineA user@machineB << END_OF_SSH_CONNECTION
# Some commands in machine B
END_OF_SSH_CONNECTION
o
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
Sin embargo, no tengo claro cómo iniciar un shell interactivo donde el usuario puede escribir comandos cuando está conectado a la máquina B. Por ejemplo, esto funciona:
ssh user@machineA -t 'bash -l -c "bash"'
y esto también funciona:
ssh -J user@machineA user@machineB -t 'bash -l -c "bash"'
Sin embargo, lo siguiente no funciona:
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.
Y tampoco lo siguiente:
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.
También probé esto:
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 versión casi funciona (es decir, no devuelve errores), pero no inicia un shell interactivo donde el usuario puede escribir comandos como esperaría.
Espero que alguien pueda ayudarme. Gracias de antemano.
Respuesta1
Gracias por la ayuda, @attie. Modifiqué ligeramente el código propuesto, que informo a continuación.
#!/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'"
en esto, que ni siquiera necesita escribir en un archivo 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
Básicamente me faltaban las comillas EOF
, utilizadas para evitar un intento de expandir el campo ${Status}
.
Respuesta2
Si desea ejecutar un script en el host remotoyobtener un shell interactivo, entonces tienes dos opciones:
- Coloque el script completo en los argumentos de la línea de comando para
ssh
. - Envíe el script al host remoto (por ejemplo: usando
scp
ossh
) y luego ejecútelo (por ejemplo: usandossh
)
1. Guión en Args
Su último ejemplo está al borde de "largo" para este enfoque, pero puedes ayudar con la legibilidad usandomapfile
(integrado bash
). Tenga en cuenta lo citado "EOF"
para evitar un intento de ampliación ${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. Presione el script y luego ejecútelo
Puntos de bonificación por usar mktemp
y limpiar después. Nota citada "EOF"
nuevamente.
Según uno de los mensajes de error proporcionados (alrededor de exec
, consulte más adelante para obtener más información), este uso cat >/tmp/myscript
probablemente no 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'"
El primer paso siempre debe ser tratar de dividir el problema en la forma más simple... En cuanto a tu último encantamiento, prueba lo siguiente:
ssh -T user@machineA << EOF
bash -l -c "bash";
EOF
¿Lo que sucede? Recibirá mensajes de bienvenida del host remoto, pero luego la sesión finaliza inmediata y silenciosamente sin errores.
Cambiando -T
(explícitamentedesactivarAsignación de PTY) para -t
(forzar asignación de PTY) proporciona una pista en la dirección correcta:
ssh -t user@machineA << EOF
bash -l -c "bash";
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.
Esto indica que está utilizando stdin
para proporcionar un script y luego también intenta conectar ese mismo stdin
(una tubería, no un terminal) al PTY remoto.
Entonces eliminemos el stdin
factor:
ssh -t user@machineA bash -l -c "bash"
¡Y funciona!
Fundamentalmente tuno puedocomparta stdin tanto con un script como con una terminal.
En cuanto a los otros errores:
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Nuevamente, analícelo para encontrar el problema. Desafortunadamente, estos comandos funcionan para mí, sospecho que porque los sistemas a los que tengo acceso están usando sh -c "${ARGS}"
o similares. Sin embargo, otro error que proporcionaste da una pista:
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Parece que su sistema está usando exec
para ejecutar el comando dado como argumento para ssh
... lo que significa que el shell no puede manejar cosas como if
o ;
para usted como espera, por lo que if
no hay un binario en la ruta y falla .
Asimismo, se dan todos los argumentos sudo
a la vez:
sudo
apt-get
update;
bash
-l
-c
"bash"
Efectivamente, sudo
el -l
argumento de (lista) es mutuamente excluyente con -c
(clase de inicio de sesión).