Mir ist gerade aufgefallen, dass wenn ich ssh [email protected]_host tail -f /some/file
ausführe , dann tail -f /some/file
läuft auf dem remote_host weiter, auch wenn die SSH-Verbindung geschlossen ist!
Also, nach mehreren Verbindungen und Trennungen, Anzahl der ausgeführten tail -f /some/file
wächst. Wie man tail -f
tatsächlich beendet wenn die SSH-Verbindung geschlossen wird?
Akzeptierte Antwort:
In
ssh host tail -f file
Die ssh
Client verbindet sich mit sshd
Server auf host
über eine TCP-Verbindung. sshd
führt tail -f
aus mit seiner Standardausgabe auf eine Pipe umgeleitet. sshd
liest, was vom anderen Ende der Pipe kommt, und kapselt es in das sshd-Protokoll, um es an ssh
zu senden Klient. (mit rshd
, tail
stdout wäre direkt der Socket gewesen, aber sshd
fügt Verschlüsselung hinzu und ist in der Lage, mehrere Streams (wie für Port/Agent/X11/Tunnel-Umleitung, stderr) auf einer einzigen TCP-Verbindung zu multiplexen, muss also auf Pipes zurückgreifen).
Wenn Sie STRG-C drücken, wird ein SIGINT an ssh
gesendet Klient. Das verursacht ssh
sterben. Beim Sterben wird die TCP-Verbindung geschlossen. Und daher auf host
, sshd
stirbt auch. tail
wird nicht getötet, aber seine Standardausgabe ist jetzt eine Pipe ohne Lesegerät am anderen Ende. Wenn es also das nächste Mal etwas in seine Standardausgabe schreibt, erhält es ein SIGPIPE und stirbt.
In:
ssh -t host 'tail -f file'
Es ist dasselbe, außer dass die Kommunikation zwischen sshd
statt mit einer Pipe erfolgt und tail
erfolgt über ein Pseudo-Terminal. tail
’s stdout ist ein Slave-Pseudo-Terminal (wie /dev/pts/12
) und was auch immer für tail
schreiben dort ist read
auf der Master-Seite (möglicherweise modifiziert durch die tty-Line-Disziplin) durch sshd
und gekapselt an ssh
gesendet Kunde.
Auf der Client-Seite mit -t
, ssh
setzt das Terminal in raw
Modus. Dies deaktiviert insbesondere den kanonischen Terminalmodus und die Handhabung von Terminalsignalen.
Also, wenn Sie Strg+C drücken , anstatt dass die Terminalleitungsdisziplin des Clients ein SIGINT an ssh
sendet Job, der nur den ^C
sendet Zeichen über die Verbindung zu sshd
und sshd
schreibt das ^C
zur Master-Seite des Remote-Terminals. Und die Leitungsdisziplin der Gegenstelle sendet ein SIGINT
tail
. tail
stirbt dann und sshd
beendet und schließt die Verbindung und ssh
beendet (wenn es nicht sonst noch mit Portweiterleitungen oder sonstigem beschäftigt ist).
Auch mit -t
, wenn die ssh
Client stirbt (z. B. wenn Sie ~.
eingeben ), wird die Verbindung geschlossen und sshd
stirbt. Als Ergebnis wird ein SIGHUP an tail
gesendet .
Passen Sie jetzt auf, dass Sie -t
verwenden hat nebenwirkungen. Beispielsweise mit den standardmäßigen Terminaleinstellungen \n
Zeichen werden in \r\n
umgewandelt und je nach entferntem System können noch mehr Dinge passieren, also sollten Sie vielleicht ein stty -opost
ausgeben (um die Nachbearbeitung der Ausgabe zu deaktivieren) auf dem entfernten Host, wenn diese Ausgabe nicht für ein Terminal bestimmt ist:
$ ssh localhost 'echo x' | hd
00000000 78 0a |x.|
00000002
$ ssh -t localhost 'echo x' | hd
00000000 78 0d 0a |x..|
00000003
$ ssh -t localhost 'stty -opost; echo x' | hd
00000000 78 0a |x.|
00000002
Ein weiterer Nachteil der Verwendung von -t
/-tt
ist, dass stdout und stderr auf dem Client nicht unterschieden werden. Sowohl stdout als auch stderr des Remote-Befehls werden in ssh
geschrieben Client-Stdout:
$ ssh localhost ls /x | wc -l
ls: cannot access /x: No such file or directory
0
$ ssh -t localhost ls /x | wc -l
1