Der Befehl ssh wird auf einem anderen System unerwartet fortgesetzt, nachdem ssh beendet wurde


11

Ich führe den folgenden Befehl aus und überwache die Ausgabedatei auf dem anderen System:

ssh $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Wenn ich den Befehl ssh mit ^Coder nur mit dem Terminal töte, an dem ich angemeldet bin, würde ich erwarten, dass auch der Remote-Befehl beendet wird. Dies ist jedoch nicht der Fall: /tmp/countErhält unabhängig davon alle Zahlen 1 bis 5 und ps -ejHzeigt, dass die Shell und ihr sleepKind weiterlaufen.

Ist dieses erwartete Verhalten und wird es irgendwo dokumentiert? Kann ich es deaktivieren? Beim Lesen hatte ich erwartet, dass ich diese Art von Verhalten explizit mit nohup aktivieren muss, nicht damit es die Standardeinstellung ist.

Ich habe in den Manpages nach ssh und sshd gesucht, aber nichts Offensichtliches entdeckt, und Google weist mich auf Anweisungen zum Aktivieren dieses Verhaltens und nicht zum Deaktivieren hin.

Ich verwende Red Hat Enterprise Linux 6.2 mit einem Root-Login und einer Bash-Shell auf beiden Systemen.

Antworten:


11

Die Antwort von uther fordert Sie auf, ein Terminal zuzuweisen, erklärt jedoch nicht, warum. Der Grund ist nicht spezifisch für ssh, sondern eine Frage der Signalerzeugung und -ausbreitung. Ich lade Sie zum Lesen ein. Was bewirkt, dass verschiedene Signale gesendet werden? für mehr Hintergrund.

Auf dem Remote-Host gibt es zwei relevante Prozesse:

  • eine Instanz des ssh-Daemons ( sshd), der die Ein- und Ausgabe des Remote-Programms an das lokale Terminal weiterleitet;
  • eine Shell, die diese forSchleife ausführt.

Die Schale kann entweder auf natürliche Weise sterben, wenn sie das Ende der Schleife erreicht oder einen schwerwiegenden Fehler aufweist, oder auf ein Signal. Die Frage ist, warum die Shell ein Signal empfangen sollte.

Wenn die Remote-Shell mit sshdOver-Pipes verbunden ist, was passiert, wenn Sie einen Befehl in der sshBefehlszeile angeben , stirbt sie an einem SIGPIPE, wenn sie beendet wird sshdund die Shell versucht, in die Pipe zu schreiben. Solange die Shell nicht in die Pipe schreibt, erhält sie kein SIGPIPE. Hier schreibt die Shell niemals etwas in ihre Standardausgabe, sodass sie für immer leben kann.

Sie können die -tOption an ssh übergeben, um es anzuweisen, ein Terminal auf der Remote-Seite zu emulieren und den angegebenen Befehl in diesem Terminal auszuführen. Wenn der SSH-Client dann verschwindet, wird sshddie Verbindung geschlossen und beendet, wodurch das Terminal zerstört wird. Wenn das Endgerät ausfällt, erhält jeder darin ausgeführte Prozess ein SIGHUP . Wenn Sie also den SSH-Client killbeenden (mit oder durch Schließen des Terminals, auf dem der Client ausgeführt wird), wird die Remote-Shell SIGHUPped.

Wenn Sie die -tOption bestehen, leitet SSH auch SIGINT weiter . Wenn Sie Ctrl+ drücken C, erhält die Remote-Shell ein SIGINT.


Verwenden Sie -ttanstelle von, -twenn ssh selbst kein tty zugewiesen hat. SSH erhält keine zugewiesene tty, wenn ssh sofort nach dem Aufruf über Optionen wie -foder im Hintergrund angezeigt wird -n.
Miron V

3

Versuchen Sie, Ihrem sshBefehl eine Pseudo-Tty zuzuweisen .

ssh -t $ip_address 'for n in 1 2 3 4 5; do sleep 10; echo $n >>/tmp/count; done'

Wenn Sie die SSH-Sitzung trennen, sollte der Prozess beendet werden.

Da dies eine Pseudo-Tty ist, wird Ihre Shell-Initialisierung wahrscheinlich keine Quellkonfigurationsdateien enthalten, sodass Ihr Befehl in einer sehr leeren Umgebung verbleibt. Möglicherweise müssen Sie eine .ssh/environmentDatei einrichten , die Umgebungsvariablen wie PATH definiert. Vonman 1 ssh

Additionally, ssh reads ~/.ssh/environment, and adds lines of the format 
“VARNAME=value” to the environment if the file exists and users are allowed
to change their environment.  For more information, see the 
PermitUserEnvironment option in sshd_config(5).

2

Alternativ zur Verwendung der -tOption ssh, den Remote-Befehl zu beenden, wenn der sshClient beendet wird oder (beendet wird), kann eine Named Pipe verwendet werden, um "EOF in SIGHUP" zu konvertieren, wenn der Standard von sshdgeschlossen wird (siehe Fehler 396 - sshd) Waisenprozesse, wenn kein Pty zugewiesen ist ).

# sample code in Bash
# press ctrl-d for EOF
ssh localhost '
TUBE=/tmp/myfifo.fifo
rm -f "$TUBE"
mkfifo "$TUBE"
#exec 3<>"$TUBE"

<"$TUBE" sleep 100 &  appPID=$!

# cf. "OpenSSH and non-blocking mode", 
# http://lists.mindrot.org/pipermail/openssh-unix-dev/2005-July/023090.html
#cat >"$TUBE"
#socat -u STDIN "PIPE:$TUBE"
dd of="$TUBE" bs=1 2>/dev/null
#while IFS="" read -r -n 1 char; do printf '%s' "$char"; done > "$TUBE"

#kill -HUP -$appPID 
kill $appPID

rm -f "$TUBE"
'

1

Dies ist der beste Weg, den ich gefunden habe, um dies zu tun. Sie möchten etwas auf der Serverseite, das versucht, stdin zu lesen, und dann die Prozessgruppe beendet, wenn dies fehlschlägt. Sie möchten jedoch auch ein stdin auf der Clientseite, das blockiert, bis der serverseitige Prozess abgeschlossen ist, und keine verbleibenden Prozesse wie <( Schlaf unendlich) könnte.

ssh localhost "sleep 99 < <(cat; kill -INT 0)" <&1

Es scheint stdout eigentlich nirgendwo umzuleiten, aber es fungiert als blockierende Eingabe und vermeidet das Erfassen von Tastenanschlägen.

Relevanter OpenSh-Fehler: https://bugzilla.mindrot.org/show_bug.cgi?id=396#c14


0

Wenn Sie dies deaktivieren möchten (scheinbar Standardverhalten), müssen Sie ssh-keep-living auf der Client- oder Serverseite aktivieren .

Wenn Sie sich die ssh-keep-alive-Optionen in den Manpages ansehen, können Sie sehen, dass sie standardmäßig deaktiviert sind.


0

Meine Antwort basiert auf Terus. Ich benötige ein ~/helperHilfsskript auf dem Server server.ip:

#!/bin/bash
TUBE=/tmp/sshCoLab_myfifo.$$;
mkfifo "$TUBE"
( <"$TUBE" "$@" ; rm "$TUBE" ; kill -TERM 0 ) &  
cat >"$TUBE" ;
rm "$TUBE" ;
kill -TERM 0 ;

Wenn es zB mit heißt

ssh server.ip ~/helper echo hello from server

und wird echo hello from serverauf server.ip ausgeführt, und dann wird der ssh-Client beendet.

Wenn es zB mit heißt

ssh server.ip ~/helper sleep 1000 &
CHID=$!

kill -9 $CHIDstoppt das Skript auch auf dem Server. Für mich kill -INT $CHIDfunktioniert das nicht, aber ich weiß nicht warum.

In der Antwort von teru wartet der Befehl ssh für immer, wenn der Remote-Befehl beendet ist, da er catniemals beendet wird.

Alle Antworten mit ssh -t haben bei mir nicht funktioniert kill, sondern nur mit Strg-C.

Bearbeiten: Ich fand heraus, dass dies von einem neuen Ubuntu 14.01 zu einer älteren wissenschaftlichen Linux-Box funktionierte - aber nicht umgekehrt. Daher denke ich, dass es keine allgemeine Lösung gibt. Seltsam.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.