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

22

Acabei de notar que, se eu executar ssh user@remote_host tail -f /some/file , então tail -f /some/file continuará executando no remote_host mesmo se a conexão ssh estiver fechada!

Então, depois de várias conexões e desconexões, o número de usuários em execução tail -f /some/file cresce. Como realmente terminar tail -f quando a conexão ssh está fechada?

    
por Dmitry Frank 01.06.2014 / 17:40

2 respostas

31

Em

ssh host tail -f file

O cliente ssh conecta-se ao servidor sshd em host em uma conexão TCP. sshd runs tail -f com seu stdout redirecionado para um pipe. sshd lê o que vem da outra extremidade do encapsulamento e o encapsula no protocolo sshd para enviar para o cliente ssh . (com rshd , tail stdout teria sido o soquete diretamente, mas sshd adiciona criptografia e é capaz de multiplexar vários fluxos (como para redirecionamento de porta / agente / X11 / túnel, stderr) em uma única conexão TCP tem que recorrer a tubos).

Quando você pressiona CTRL-C, uma SIGINT é enviada ao cliente ssh . Isso faz com que ssh morra. Ao morrer, a conexão TCP é fechada. E, portanto, em host , sshd também morre. tail não é morto, mas seu stdout é agora um pipe 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 pipe, a comunicação entre sshd e tail é feita por meio de um pseudo-terminal. O stdout de tail é um pseudo-terminal escravo (como /dev/pts/12 ) e qualquer que seja o tail escreve existe read no lado mestre (possivelmente modificado pela tty line disciplina) por sshd e enviado encapsulado para o cliente ssh .

No lado do cliente, com -t , ssh coloca o terminal no modo raw . Em particular, isso desativa o modo canônico do terminal e o manuseio do sinal do terminal.

Então, quando você pressiona Ctrl + C , ao invés da disciplina de linha de terminal do cliente enviar uma SIGINT para o trabalho ssh , isso apenas envia o caractere ^C sobre a conexão para sshd e sshd escreve que ^C para o lado mestre do terminal remoto. E a disciplina de linha do terminal remoto envia um SIGINT para tail . tail então morre, e sshd sai e fecha a conexão e ssh termina (se ainda não estiver ocupado com encaminhamentos de porta ou outros).

Além disso, com -t , se o cliente ssh morrer (por exemplo, se você inserir ~. ), a conexão será fechada e sshd será interrompido. Como resultado, um SIGHUP será enviado para tail .

Agora, esteja ciente de que usar -t tem efeitos colaterais. Por exemplo, com as configurações padrão do terminal, \n caracteres são convertidos em \r\n e mais coisas podem acontecer dependendo do sistema remoto, então você pode querer emitir um stty -opost (para desabilitar o pós-processamento de saída) no host remoto se essa saída não for destinada 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 stdout do ssh 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
    
por 01.06.2014 / 22:03
11

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

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

ou até mesmo

ssh -tt user@remote_host tail -f /some/file
    
por 01.06.2014 / 17:59