1. Guión en Args

1. Guión en Args

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:

  1. Coloque el script completo en los argumentos de la línea de comando para ssh.
  2. Envíe el script al host remoto (por ejemplo: usando scpo ssh) y luego ejecútelo (por ejemplo: usando ssh)

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 mktempy 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/myscriptprobablemente 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 stdinpara proporcionar un script y luego también intenta conectar ese mismo stdin(una tubería, no un terminal) al PTY remoto.

Entonces eliminemos el stdinfactor:

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 execpara ejecutar el comando dado como argumento para ssh... lo que significa que el shell no puede manejar cosas como ifo ;para usted como espera, por lo que ifno hay un binario en la ruta y falla .

Asimismo, se dan todos los argumentos sudoa la vez:

  1. sudo
  2. apt-get
  3. update;
  4. bash
  5. -l
  6. -c
  7. "bash"

Efectivamente, sudoel -largumento de (lista) es mutuamente excluyente con -c(clase de inicio de sesión).

información relacionada