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?

Dmitry Frank
fonte

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
Stéphane Chazelas
fonte
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
Hauke ​​Laging
fonte
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