Como terminar remotamente chamado "tail -f" quando a conexão é fechada?


24

Acabei de notar que, se eu executar ssh user@remote_host tail -f /some/file, tail -f /some/filecontinuará sendo executado no remote_host, mesmo que a conexão ssh esteja fechada!

Assim, depois de várias conexões e desconexões, o número de execuções tail -f /some/fileaumenta. Como realmente terminar tail -fquando a conexão ssh está fechada?

Respostas:


33

Em

ssh host tail -f file

O sshcliente se conecta ao sshdservidor em hostuma conexão TCP. sshdé executado tail -fcom seu stdout redirecionado para um pipe. sshdlê o que está vindo da outra extremidade do pipe e o encapsula no protocolo sshd para enviar ao sshcliente. (com rshd, tailstdout teria sido o soquete diretamente, mas sshdadiciona criptografia e é capaz de multiplexar vários fluxos (como para porta / agente / X11 / redirecionamento de túnel, stderr) em uma única conexão TCP, portanto, é necessário recorrer a pipes).

Quando você pressiona CTRL-C, um SIGINT é enviado ao sshcliente. Isso causa ssha morte. Ao morrer, a conexão TCP é fechada. E, portanto, em host, sshdmorre também. tailnão é morto, mas agora o stdout é um cano sem leitor na outra extremidade. Então, da próxima vez que escrever algo em seu stdout, ele receberá um SIGPIPE e morrerá.

Em:

ssh -t host 'tail -f file'

É a mesma coisa, exceto que, em vez de estar com um cano, a comunicação entre sshde tailé via pseudo-terminal. tailO stdout é um pseudo-terminal escravo (como /dev/pts/12) e qualquer tailgravação existente readno lado mestre (possivelmente modificada pela disciplina da linha tty) sshde enviada encapsulada para o sshcliente.

No lado do cliente, com -t, sshcoloca o terminal no rawmodo. Em particular, isso desativa o modo canônico do terminal e a manipulação do sinal do terminal.

Portanto, quando você pressiona Ctrl+C, em vez da disciplina da linha de terminal do cliente enviar um SIGINT para o sshtrabalho, ele envia o ^Ccaractere pela conexão sshde o sshdgrava ^Cno lado principal do terminal remoto. E a disciplina de linha do terminal remoto envia um SIGINTpara tail. tailentão morre, sshdsai e fecha a conexão e sshtermina (se ainda não estiver ocupado com o encaminhamento de porta ou outro).

Além disso, com -t, se o sshcliente morre (por exemplo, se você entrar ~.), a conexão é fechada e sshdmorre. Como resultado, um SIGHUP será enviado para tail.

Agora, tenha cuidado que o uso -ttem efeitos colaterais. Por exemplo, com as configurações padrão do terminal, os \ncaracteres são convertidos \r\ne outras coisas podem acontecer, dependendo do sistema remoto; portanto, você pode emitir um stty -opost(para desativar o pós-processamento da saída) no host remoto, se essa saída não se destina a um 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

Outra desvantagem de usar -t/ -tté que stdout e stderr não são diferenciados no cliente. O stdout e o stderr do comando remoto serão gravados no sshstdout do 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

Muito obrigado por uma explicação tão detalhada! Eu gostaria de poder aceitar duas respostas ..
— Dmitry Frank

"with -t, se o sshcliente morrer (por exemplo, se você entrar ~.)" O que é mesmo ~.?
— x-yuri

11
@ x-yuri, ~.é a sequência de escape que você digita para desconectar o cliente. Veja man sshpara detalhes.
— Stéphane Chazelas

11

Você precisa de alocação de terminal no lado remoto:

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

ou mesmo

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

11
Obrigado, ambos -tou -ttfunciona. Mas ainda não consigo entender o motivo real disso: digamos, quando eu chamo shell remotamente e fecho a conexão, o shell é encerrado. Mas tail -fnão é. É claro que eu já li sobre a -topção man ssh, mas não ajudou muito. Parece que eu não entendo alguns genéricos e ficaria feliz se você sugerir alguns documentos para ler sobre isso ou provavelmente explicar você mesmo. Obrigado!
— Dmitry Frank

2
@DmitryFrank Meu entendimento é o seguinte: se a conexão for interrompida, sshdenviará a SIGHUP. Mas onde nenhum terminal é, não pode haver desligamento conexão do terminal ...
— Hauke Laging

Obrigado, vou ler sobre SIGHUPe outros sinais, ainda sei quase nada sobre isso.
— Dmitry Frank

fyi: Eu apenas tentei correr tail -f, então eu abri htope enviei SIGHUPa ele (pressionando F9-> 1-> Enter) e tail -fé encerrado! Assim, a razão deve ser algum diferente ..
— Dmitry Frank

3
@DmitryFrank Você entendeu mal o problema. O problema não é o qual tailnão reagiria SIGHUP. O problema é que SIGHUP** não é enviado `para tailsem um pseudo terminal. Você pode ver isso anexando stracea tailambos os casos.
— Hauke ​​Laging
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.