Je viens de remarquer que si j'exécute ssh [email protected]_host tail -f /some/file
, puis tail -f /some/file
continue de fonctionner sur le remote_host même si la connexion ssh est fermée !
Ainsi, après plusieurs connexions et déconnexions, nombre de tail -f /some/file
en cours d'exécution grandit. Comment terminer réellement tail -f
lorsque la connexion ssh est fermée ?
Réponse acceptée :
Dans
ssh host tail -f file
Le ssh
le client se connecte au sshd
serveur sur host
via une connexion TCP. sshd
exécute tail -f
avec sa sortie standard redirigée vers un tube. sshd
lit ce qui vient de l'autre bout du tuyau et l'encapsule dans le protocole sshd pour l'envoyer au ssh
client. (avec rshd
, tail
stdout aurait été le socket directement, mais sshd
ajoute le cryptage et est capable de multiplexer plusieurs flux (comme pour la redirection port/agent/X11/tunnel, stderr) sur une seule connexion TCP, il faut donc recourir à des canaux).
Lorsque vous appuyez sur CTRL-C, un SIGINT est envoyé au ssh
client. Cela provoque ssh
mourir. En mourant, la connexion TCP est fermée. Et donc, sur host
, sshd
meurt aussi. tail
n'est pas tué, mais sa sortie standard est maintenant un canal sans lecteur à l'autre bout. Ainsi, la prochaine fois qu'il écrira quelque chose sur sa sortie standard, il recevra un SIGPIPE et mourra.
Dans :
ssh -t host 'tail -f file'
C'est la même chose sauf qu'au lieu d'être avec un tuyau, la communication entre sshd
et tail
se fait via un pseudo-terminal. tail
's stdout est un pseudo-terminal esclave (comme /dev/pts/12
) et quelle que soit la tail
écrire il y a read
côté maître (éventuellement modifié par la discipline de la ligne tty) par sshd
et envoyé encapsulé au ssh
client.
Côté client, avec -t
, ssh
met le terminal en raw
mode. En particulier, cela désactive le mode canonique du terminal et la gestion des signaux du terminal.
Ainsi, lorsque vous appuyez sur Ctrl+C , au lieu que la discipline de la ligne terminale du client envoie un SIGINT au ssh
job, qui envoie juste le ^C
caractère sur la connexion à sshd
et sshd
écrit que ^C
au côté maître du terminal distant. Et la discipline de ligne du terminal distant envoie un SIGINT
à tail
. tail
puis meurt, et sshd
quitte et ferme la connexion et ssh
se termine (s'il n'est pas autrement toujours occupé avec des transferts de port ou autre).
Aussi, avec -t
, si le ssh
le client meurt (par exemple si vous saisissez ~.
), la connexion est fermée et sshd
meurt. En conséquence, un SIGHUP sera envoyé à tail
.
Maintenant, méfiez-vous que l'utilisation de -t
a des effets secondaires. Par exemple, avec les paramètres par défaut du terminal, \n
les caractères sont convertis en \r\n
et plus de choses peuvent se produire en fonction du système distant, vous pouvez donc vouloir émettre un stty -opost
(pour désactiver le post-traitement de la sortie) sur l'hôte distant si cette sortie n'est pas destinée à un 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
Un autre inconvénient de l'utilisation de -t
/-tt
est que stdout et stderr ne sont pas différenciés sur le client. Le stdout et le stderr de la commande à distance seront écrits dans le ssh
sortie standard du client :
$ ssh localhost ls /x | wc -l
ls: cannot access /x: No such file or directory
0
$ ssh -t localhost ls /x | wc -l
1