Wie kann man "tail -f" aus der Ferne beenden, wenn die Verbindung geschlossen ist?

24

Mir ist gerade aufgefallen, dass, wenn ich es ausführe ssh user@remote_host tail -f /some/file, es tail -f /some/fileauf dem remote_host weiterläuft, auch wenn die ssh-Verbindung geschlossen ist!

Nachdem mehrere Verbindungen hergestellt und getrennt wurden, steigt die Anzahl der laufenden Verbindungen tail -f /some/file. Wie kann man eigentlich kündigen, tail -fwenn die SSH-Verbindung geschlossen ist?

Dmitry Frank
quelle

Antworten:

33

Im

ssh host tail -f file

Der sshClient stellt über eine TCP-Verbindung eine Verbindung zum sshdServer her host. sshdLäuft tail -fmit seiner Standardausgabe auf eine Pipe umgeleitet. sshdLiest, was vom anderen Ende der Pipe kommt, und kapselt es in das sshd-Protokoll, um es an den sshClient zu senden . (mit rshd, tailstdout wäre der Socket direkt gewesen, sshdfügt aber Verschlüsselung hinzu und kann mehrere Streams (wie für Port / Agent / X11 / Tunnel Redirection, stderr) auf einer einzigen TCP-Verbindung multiplexen, muss also auf Pipes zurückgreifen).

Wenn Sie STRG-C drücken, wird ein SIGINT an den sshClient gesendet . Das lässt sshsterben. Nach dem Tod wird die TCP-Verbindung geschlossen. Und deshalb auf host, sshdstirbt auch. tailwird nicht getötet, aber sein stdout ist jetzt eine Pfeife ohne Leser am anderen Ende. Wenn es das nächste Mal etwas auf seine Standardausgabe schreibt, erhält es eine SIEGELROHR und stirbt.

Im:

ssh -t host 'tail -f file'

Es ist dasselbe mit der Ausnahme, dass die Kommunikation zwischen sshdund tailüber ein Pseudo-Terminal statt über eine Pipe erfolgt . tailstdout ist ein Slave-Pseudo-Terminal (wie /dev/pts/12) und was tailauch immer readauf der Masterseite geschrieben wird (möglicherweise durch die tty-Zeilendisziplin modifiziert) sshdund wird gekapselt an den sshClient gesendet .

Auf der Client - Seite mit -t, sshsetzt das Terminal in rawBetrieb. Dies deaktiviert insbesondere den kanonischen Terminalmodus und die Terminal-Signalverarbeitung.

Also, wenn Sie drücken Ctrl+C, statt der Client-Terminal - Linie Disziplin ein SIGINT zum Senden sshJob, dass sendet nur den ^CCharakter über die Verbindung zu sshdund sshdschreibt , dass ^Cauf die Master - Seite des entfernten Terminals. Und die Leitungsdisziplin der Gegenstelle sendet ein SIGINTan tail. taildann stirbt sshdund sshbeendet und schließt die Verbindung und beendet sich (wenn es sonst noch nicht mit Portweiterleitungen oder anderem beschäftigt ist).

Auch mit -t, wenn die sshClient - Formen (zum Beispiel , wenn Sie eingeben ~.), wird die Verbindung geschlossen und sshdstirbt. Als Ergebnis wird ein SIGHUP an gesendet tail.

Achten Sie jetzt darauf, dass die Verwendung von -tNebenwirkungen hat. Beispielsweise werden mit den Standardeinstellungen des Terminals \nZeichen in konvertiert, \r\nund je nach Remotesystem können weitere Vorgänge auftreten. Sie können daher auf dem Remotehost ein stty -opost(zum Deaktivieren der Ausgabennachverarbeitung) ausgeben, wenn diese Ausgabe nicht vorgesehen ist ein Terminal:

$ 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/ -ttist, dass stdout und stderr auf dem Client nicht unterschieden werden. Sowohl stdout als auch stderr des Remote-Befehls werden in die sshstdout des Clients geschrieben:

$ ssh localhost ls /x  | wc -l
ls: cannot access /x: No such file or directory
0
$ ssh -t localhost ls /x | wc -l
1
Stéphane Chazelas
quelle
Vielen Dank für eine so ausführliche Erklärung! Ich wünschte, ich könnte zwei Antworten akzeptieren ..
Dmitry Frank
"mit -t, wenn der sshClient stirbt (zB wenn Sie eintreten ~.)" Was ist ~.nochmal?
X-Yuri
1
@ x-yuri, ~.ist die Escape-Sequenz, die Sie eingeben, um den Client zu trennen. Siehe man sshfür weitere Einzelheiten.
Stéphane Chazelas
11

Sie benötigen eine Terminalzuordnung auf der Remote-Seite:

ssh -t user@remote_host tail -f /some/file

oder auch

ssh -tt user@remote_host tail -f /some/file
Hauke ​​Laging
quelle
1
Danke, beides -toder -ttfunktioniert. Aber ich kann den wahren Grund dafür immer noch nicht verstehen: Sagen wir, wenn ich die Shell aus der Ferne aufrufe und die Verbindung beende, wird die Shell beendet. Geht tail -faber nicht. Natürlich habe ich schon über -tOption in gelesen man ssh, aber es hat nicht viel geholfen. Anscheinend verstehe ich einige Generika nicht, und ich würde mich freuen, wenn Sie einige Dokumente vorschlagen, um darüber zu lesen, oder es wahrscheinlich selbst erklären. Vielen Dank!
Dmitry Frank
2
@DmitryFrank Mein Verständnis ist folgendes: Wenn die Verbindung unterbrochen wird, sshdsendet a SIGHUP. Aber wo kein Terminal ist, kann es kein Auflegen der Terminalverbindung geben ...
Hauke ​​Laging
Danke, ich werde darüber lesen SIGHUPund andere Signale, weiß noch fast nichts darüber.
Dmitry Frank
fyi: Ich habe gerade versucht zu rennen tail -f, dann habe ich es geöffnet htopund gesendet SIGHUP(durch Drücken von F9-> 1-> Enter) und es tail -fwird beendet! Also, Grund sollte etwas anders sein ..
Dmitry Frank
3
@DmitryFrank Du hast das Problem falsch verstanden. Das Problem ist nicht, dass tailnicht reagiert würde SIGHUP. Das Problem ist, dass SIGHUPnicht tailohne Pseudo-Terminal gesendet wird . Sie können sehen , dass durch das Anbringen stracean tailFällen in beiden.
Hauke ​​Laging