¿Cómo terminar remotamente llamado "tail -f" cuando la conexión está cerrada?

24

Me acabo de dar cuenta de que si ejecuto ssh user@remote_host tail -f /some/file, ¡ tail -f /some/filesigue ejecutándose en remote_host incluso si la conexión ssh está cerrada!

Entonces, después de varias conexiones y desconexiones, el número de carreras tail -f /some/fileaumenta. ¿Cómo terminar realmente tail -fcuando la conexión ssh está cerrada?

Dmitry Frank
fuente

Respuestas:

33

En

ssh host tail -f file

El sshcliente se conecta al sshdservidor a hosttravés de una conexión TCP. sshdse ejecuta tail -fcon su stdout redirigido a una tubería. sshdlee lo que viene del otro extremo de la tubería y lo encapsula en el protocolo sshd para enviarlo al sshcliente. (con rshd, tailstdout habría sido el socket directamente, pero sshdagrega cifrado y es capaz de multiplexar varias secuencias (como para redirección de puerto / agente / X11 / túnel, stderr) en una sola conexión TCP, por lo que tiene que recurrir a tuberías).

Cuando presiona CTRL-C, se envía un SIGINT al sshcliente. Eso hace sshque muera. Al morir, la conexión TCP se cierra. Y por lo tanto, en host, sshdmuere también. tailno se mata, pero su stdout ahora es una tubería sin lector en el otro extremo. Entonces, la próxima vez que escriba algo en su stdout, recibirá un SIGPIPE y morirá.

En:

ssh -t host 'tail -f file'

Es lo mismo, excepto que en lugar de estar con una tubería, la comunicación entre sshdy tailes a través de un pseudo-terminal. tailEl stdout es un pseudo-terminal esclavo (como /dev/pts/12) y cualquier tailescritura que haya readen el lado maestro (posiblemente modificada por la disciplina de línea tty) sshdy enviada encapsulada al sshcliente.

En el lado del cliente, con -t, sshpone el terminal en rawmodo. En particular, eso desactiva el modo canónico del terminal y el manejo de la señal del terminal.

Entonces, cuando presiona Ctrl+C, en lugar de que la disciplina de la línea de terminal del cliente envíe un SIGINT al sshtrabajo, simplemente envía el ^Ccarácter a través de la conexión sshdy lo sshdescribe ^Cen el lado maestro del terminal remoto. Y la disciplina de línea del terminal remoto envía un SIGINTa tail. tailluego muere, sshdsale y cierra la conexión y sshfinaliza (si no está ocupado con reenvíos de puertos u otros).

Además, con -t, si el sshcliente muere (por ejemplo, si ingresa ~.), la conexión se cierra y sshdmuere. Como resultado, se enviará un SIGHUP a tail.

Ahora, tenga en cuenta que el uso -ttiene efectos secundarios. Por ejemplo, con la configuración predeterminada del terminal, los \ncaracteres se convierten \r\ny pueden suceder más cosas dependiendo del sistema remoto, por lo que es posible que desee emitir un stty -opost(para deshabilitar el procesamiento posterior de la salida) en el host remoto si esa salida no está destinada a una 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

Otro inconveniente de usar -t/ -ttes que stdout y stderr no están diferenciados en el cliente. Tanto el stdout como el stderr del comando remoto se escribirán en el sshstdout del cliente:

$ 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
fuente
¡Muchas gracias por una explicación tan detallada! Desearía poder aceptar dos respuestas ...
Dmitry Frank
"con -t, si el sshcliente muere (por ejemplo, si ingresa ~.)" ¿Qué es ~.nuevamente?
x-yuri
1
@ x-yuri, ~.es la secuencia de escape que ingresas para desconectar al cliente. Ver man sshpara más detalles.
Stéphane Chazelas
11

Necesita asignación de terminal en el lado remoto:

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

o incluso

ssh -tt user@remote_host tail -f /some/file
Hauke ​​Laging
fuente
1
Gracias, ambos -to -ttfunciona. Pero todavía no puedo entender la verdadera razón de esto: por ejemplo, cuando llamo a Shell de forma remota y cierro la conexión, Shell finaliza. Pero tail -fno lo es. Por supuesto, ya he leído sobre la -topción man ssh, pero no ayudó mucho. Parece que no entiendo algunos genéricos, y me alegraría si sugieres algunos documentos para leer sobre ellos, o probablemente te los expliques tú mismo. ¡Gracias!
Dmitry Frank
2
@DmitryFrank Tengo entendido lo siguiente: si la conexión se rompe, entonces sshdenvía un SIGHUP. Pero donde no hay terminal, no puede haber una conexión de terminal ...
Hauke ​​Laging
Gracias, leeré sobre SIGHUPy otras señales, todavía no sé casi nada al respecto.
Dmitry Frank
FYI: Acabo de intentar ejecutar tail -f, luego lo abrí htopy lo envié SIGHUP(presionando F9-> 1-> Enter), ¡y tail -fse terminó! Entonces, la razón debería ser diferente ...
Dmitry Frank
3
@DmitryFrank Has entendido mal el problema. El problema no es que tailno reaccionaría SIGHUP. El problema es que SIGHUP** no se envía` tailsin un pseudo terminal. Se puede ver que uniendo stracea tailque en ambos casos.
Hauke ​​Laging