
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:
- Fügen Sie das gesamte Skript in die Befehlszeilenargumente für ein
ssh
. - Übertragen Sie das Skript an den Remote-Host (z. B. mit
scp
oderssh
) und führen Sie es anschließend aus (z. B. mitssh
).
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 mktemp
und 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/myscript
wird 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 stdin
ein Skript bereitstellen und dann auch versuchen, dasselbe stdin
(eine Pipe, kein Terminal) mit dem Remote-PTY zu verbinden.
Entfernen wir also den stdin
Faktor:
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 exec
den als Argumente angegebenen Befehl ausführt ..., was bedeutet, dass die Shell nicht in der Lage ist, die Dinge so oder für Sie ssh
zu 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 sudo
auf einmal angegeben:
sudo
apt-get
update;
bash
-l
-c
"bash"
Natürlich schließen sich sudo
das (Listen-)Argument und die (Anmeldeklasse) gegenseitig aus.-l
-c