1. Skript in Args

1. Skript in Args

Angenommen, ich möchte mich über Maschine A mit Maschine B verbinden. Wie ich gelernt habe, gibt es mehrere Möglichkeiten, dies zu erreichen, zum Beispiel

ssh -T -J user@machineA user@machineB << END_OF_SSH_CONNECTION
  # Some commands in machine B
END_OF_SSH_CONNECTION

oder

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

Mir ist jedoch nicht klar, wie ich eine interaktive Shell starten kann, in der der Benutzer Befehle eingeben kann, wenn er mit Maschine B verbunden ist. So funktioniert es beispielsweise:

ssh user@machineA -t 'bash -l -c "bash"'

und das hier funktioniert auch:

ssh -J user@machineA user@machineB -t 'bash -l -c "bash"'

Folgendes funktioniert jedoch nicht:

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.

Und auch nicht das Folgende:

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.

Ich habe auch Folgendes versucht:

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

Diese letzte Version funktioniert fast (d. h. sie gibt keine Fehler zurück), startet jedoch keine interaktive Shell, in die der Benutzer Befehle eingeben kann, wie ich es erwarten würde.

Ich hoffe, dass mir jemand helfen kann. Vielen Dank im Voraus.

Antwort1

Danke für die Hilfe, @attie. Ich habe deinen vorgeschlagenen Code leicht modifiziert, den ich hier unten berichte.

#!/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'"

hinein, das nicht einmal in eine externe Datei schreiben muss.

#!/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

Mir fehlten im Wesentlichen die Anführungszeichen um EOF, die verwendet werden, um einen Versuch der Felderweiterung zu vermeiden ${Status}.

Antwort2

Wenn Sie ein Skript auf dem Remote-Host ausführen möchtenUndWenn Sie eine interaktive Shell erhalten möchten, haben Sie zwei Möglichkeiten:

  1. Fügen Sie das gesamte Skript in die Befehlszeilenargumente für ein ssh.
  2. Übertragen Sie das Skript an den Remote-Host (z. B. mit scpoder ssh) und führen Sie es anschließend aus (z. B. mit ssh).

1. Skript in Args

Ihr letztes Beispiel steht kurz vor „lang" für diesen Ansatz, aber Sie können die Lesbarkeit verbessern, indem Sie verwendenmapfile(ein integriertes Element in bash). Beachten Sie das Anführungszeichen "EOF", um einen Versuch der Erweiterung zu vermeiden ${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. Skript pushen, dann ausführen

Bonuspunkte für die Verwendung mktempund das anschließende Aufräumen. Hinweis "EOF"erneut zitiert.

Basierend auf einer der von Ihnen bereitgestellten Fehlermeldungen (um exec, siehe unten für weitere Informationen) cat >/tmp/myscriptwird diese Verwendung von wahrscheinlich nicht funktionieren.

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'"

Der erste Schritt sollte immer darin bestehen, das Problem auf die einfachste Form herunterzubrechen. Versuchen Sie es mit Ihrem letzten Zauberspruch stattdessen mit Folgendem:

ssh -T user@machineA << EOF
  bash -l -c "bash";
EOF

Was passiert? Sie erhalten zwar alle Willkommensnachrichten vom Remote-Host, aber dann wird die Sitzung sofort und ohne Fehlermeldung beendet.

Ändern -T(explizitdeaktivierenPTY-Zuweisung) für -t(PTY-Zuweisung erzwingen) gibt einen Hinweis in die richtige Richtung:

ssh -t user@machineA << EOF
  bash -l -c "bash";
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.

Dies weist darauf hin, dass Sie stdinein Skript bereitstellen und dann auch versuchen, dasselbe stdin(eine Pipe, kein Terminal) mit dem Remote-PTY zu verbinden.

Entfernen wir also den stdinFaktor:

ssh -t user@machineA bash -l -c "bash"

Und es funktioniert!

Im Grundekann nichtTeilen Sie die Standardeingabe sowohl mit einem Skript als auch mit einem Terminal.


Zu den anderen Fehlern:

E: Command line option 'l' [from -l] is not understood in combination with the other options.

Zerlegen Sie es noch einmal, um das Problem zu finden. Leider funktionieren diese Befehle bei mir, ich vermute, weil die Systeme, auf die ich Zugriff habe, Folgendes verwenden sh -c "${ARGS}"oder Ähnliches. Ein anderer von Ihnen angegebener Fehler gibt jedoch einen Hinweis:

/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found

Es sieht so aus, als ob Ihr System execden als Argumente angegebenen Befehl ausführt ..., was bedeutet, dass die Shell nicht in der Lage ist, die Dinge so oder für Sie sshzu handhaben, wie Sie es sich erhoffen. Daher befindet sich keine Binärdatei auf dem Pfad und der Vorgang schlägt fehl.if;if

Ebenso werden alle Argumente sudoauf einmal angegeben:

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

Natürlich schließen sich sudodas (Listen-)Argument und die (Anmeldeklasse) gegenseitig aus.-l-c

verwandte Informationen