Einen Befehl über SSH ausführen

Setzen Sie den Befehl hinter den Host, in einfache Anführungszeichen: ssh user@server 'uptime | cut -c1-20'. Er läuft auf dem Server, seine Ausgabe kommt zu Ihnen zurück, und ssh endet mit dem Exit-Code des Befehls, oder mit 255, wenn SSH selbst gescheitert ist. Einfache Anführungszeichen verhindern, dass Ihre lokale Shell den Befehl verändert. Fügen Sie -n hinzu, wenn Sie ssh in einer Schleife verwenden.

Derselbe Befehl auf vielen Servern? Wardterm führt ihn auf allen aus und zeigt jedes Ergebnis. Zeigen

Aktualisiert am . OpenSSH 10.3 unter macOS zu OpenSSH 10.0 unter Debian 13 in einem Wegwerf-Container, mit bash auf beiden Seiten.

Quoting: welche Shell liest was

Zwei Shells lesen Ihren Befehl: zuerst Ihre eigene, dann die auf dem Server. Die Anführungszeichen bestimmen, welche Shell was auflöst.

NAME=local
ssh server "echo $NAME"       # local shell expands it, prints: local
ssh server 'echo $HOME $NAME' # server expands it, prints: /home/tester
                              # NAME does not exist on the server

ssh verbindet seine Argumente mit einzelnen Leerzeichen und sendet eine einzige Zeichenkette, Anführungszeichen, die nur Ihre lokale Shell sieht, gehen daher verloren:

$ ssh server echo "a  b"
a b
$ ssh server 'echo "a  b"'
a  b

Dasselbe gilt für Pipes. Der erste Befehl unten führt wc auf dem Server aus, der zweite auf Ihrem Rechner:

ssh server 'ls /tmp | wc -l'
ssh server ls /tmp | wc -l

Um einen lokalen Wert mit Leerzeichen oder Anführungszeichen zu übergeben, lassen Sie bash ihn maskieren:

F="a b'c"
ssh server "printf '%s\n' $(printf %q "$F")"

Mehrere Zeilen: ein Heredoc

Setzen Sie die Heredoc-Markierung in Anführungszeichen, dann wird lokal nichts aufgelöst:

ssh server 'bash -s' <<'REMOTE'
echo "user: $(whoami)"
cd /tmp && pwd
REMOTE

Ohne Anführungszeichen um die Markierung löst Ihre lokale Shell Variablen zuerst auf. Maskieren Sie diejenigen, die für den Server gedacht sind:

V=abc
ssh server 'bash -s' <<REMOTE
echo "local var: $V, remote: \$HOSTNAME"
REMOTE

Ein lokales Skript mit Argumenten auf dem Server ausführen:

ssh server 'bash -s -- one two' < script.sh

Exit-Codes

BefehlExit-Code
ssh server 'exit 3'3
ssh server 'false; true'0, weil nur der letzte Befehl zählt
ssh server 'set -e; false; echo no'1, und er stoppt bei false
ssh server nosuchcmd127, Befehl auf dem Server nicht gefunden
ssh -p 1 server true255, SSH konnte keine Verbindung herstellen

Ein Remote-Befehl kann auch von sich aus mit 255 enden, 255 deutet also nur auf einen SSH-Fehler hin. Die Standardfehlerausgabe bleibt von der Standardausgabe getrennt, daher funktionieren 2>/dev/null und > file auf Ihrer Seite wie gewohnt.

Warum ssh in einer Schleife nach einem Host stoppt

ssh liest die Standardeingabe und sendet sie an den Server, so frisst es den Rest der Liste. Diese Schleife lief in unserem Test nur einmal, bei drei Zeilen in der Datei:

while read -r h; do ssh "$h" uptime; done < hosts

Mit -n liest ssh die Standardeingabe nicht. Diese Schleife lief dreimal:

while read -r h; do ssh -n "$h" uptime; done < hosts

Bevor Sie eine Schleife über Produktionsserver laufen lassen, lesen Sie Fehler auf Produktionsservern vermeiden.

Daten über die Standardeingabe senden

Ohne -n ist die Standardeingabe nützlich. Remote-Befehle können sie lesen:

printf 'hello\n' | ssh server 'tr a-z A-Z'
tar -cf - folder | ssh server 'tar -C /tmp -xf -'

Befehle, die ein Terminal brauchen

Mit einem Befehl fordert ssh kein Terminal an, deshalb gibt tty die Meldung not a tty aus, und sudo kann nicht nach einem Passwort fragen:

sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper

Fügen Sie -t für interaktive Programme hinzu:

ssh -t server sudo systemctl restart nginx

Ist Ihre eigene Standardeingabe kein Terminal, zum Beispiel in einem Skript, gibt -t die Meldung Pseudo-terminal will not be allocated because stdin is not a terminal aus. Erzwingen Sie es mit -tt, und lesen Sie die Anleitung zu diesem Fehler.

Lange Aufgaben und Hintergrundbefehle

Ein Hintergrundjob, der die Ausgabe noch offen hält, lässt ssh warten. Der erste Befehl unten dauerte in unserem Test 2 Sekunden, der zweite kehrte sofort zurück:

ssh server 'sleep 2 &'
ssh server 'nohup sleep 2 >/dev/null 2>&1 &'

Für echte Arbeit, die die Verbindung überleben muss, nutzen Sie tmux auf dem Server. ssh -f server 'command' schickt nur Ihr lokales ssh nach der Anmeldung in den Hintergrund.

Die Umgebung unterscheidet sich von Ihrer Anmeldung

Ein Befehl über SSH läuft nicht in einer Login-Shell, Dateien wie ~/.profile werden also nicht gelesen. In unserem Test gab shopt login_shell den Wert off aus, und PATH war /usr/local/bin:/usr/bin:/bin:/usr/games. Funktioniert ein Befehl von Hand, meldet aber über SSH command not found, verwenden Sie seinen vollständigen Pfad.

Fragen

Wie führe ich sudo über SSH ohne den Terminal-Fehler aus?

Ergänzen Sie -t, etwa ssh -t server sudo systemctl restart nginx, damit sudo ein Terminal für die Passwortabfrage hat. In Skripten nutzen Sie -tt oder richten sudo für diesen Befehl ein.

Warum funktioniert ein Befehl von Hand, aber nicht über SSH?

Ein Befehl über SSH läuft in keiner Login-Shell, daher wird ~/.profile nicht gelesen und PATH ist kürzer. Verwenden Sie den vollständigen Pfad des Programms.

Wie führe ich mehrere Befehle in einem SSH-Aufruf aus?

Schreiben Sie sie in eine Zeichenkette in Anführungszeichen, etwa ssh server 'cd /tmp && ls', oder senden Sie ein Skript mit ssh server 'bash -s' < script.sh.

Quellen

Mehr zu Sitzungen und tmux

Alle Anleitungen