Ho appena notato che se eseguo ssh [email protected]_host tail -f /some/file
, quindi tail -f /some/file
continua a funzionare su remote_host anche se la connessione ssh è chiusa!
Quindi, dopo diverse connessioni e disconnessioni, numero di tail -f /some/file
in esecuzione cresce. Come terminare effettivamente tail -f
quando la connessione ssh è chiusa?
Risposta accettata:
In
ssh host tail -f file
Il ssh
il client si connette a sshd
server su host
su una connessione TCP. sshd
esegue tail -f
con il suo stdout reindirizzato a una pipe. sshd
legge ciò che proviene dall'altra estremità della pipe e lo incapsula nel protocollo sshd per inviarlo a ssh
cliente. (con rshd
, tail
stdout sarebbe stato direttamente il socket, ma sshd
aggiunge la crittografia ed è in grado di multiplexare diversi flussi (come per port/agent/X11/tunnel redirection, stderr) su una singola connessione TCP, quindi deve ricorrere alle pipe).
Quando premi CTRL-C, viene inviato un SIGINT a ssh
cliente. Ciò causa ssh
morire. Alla morte, la connessione TCP viene chiusa. E quindi, su host
, sshd
muore anche lui. tail
non viene ucciso, ma il suo stdout ora è una pipe senza lettore all'altra estremità. Quindi, la prossima volta che scrive qualcosa nel suo stdout, riceverà un SIGPIPE e morirà.
In:
ssh -t host 'tail -f file'
È la stessa cosa tranne che invece di essere con una pipe, la comunicazione tra sshd
e tail
avviene tramite uno pseudo-terminale. tail
's stdout è uno pseudo-terminale slave (come /dev/pts/12
) e qualunque tail
scrivi c'è read
sul lato master (possibilmente modificato dalla disciplina della linea tty) da sshd
e inviato incapsulato a ssh
cliente.
Sul lato client, con -t
, ssh
mette il terminale in raw
modalità. In particolare, ciò disabilita la modalità canonica del terminale e la gestione del segnale del terminale.
Quindi, quando premi Ctrl+C , invece della disciplina della linea terminale del client che invia un SIGINT a ssh
job, che invia semplicemente il ^C
carattere sulla connessione a sshd
e sshd
scrive quel ^C
al lato master del terminale remoto. E la disciplina di linea del terminale remoto invia un SIGINT
a tail
. tail
poi muore e sshd
esce e chiude la connessione e ssh
termina (se non è altrimenti ancora occupato con port forwarding o altro).
Inoltre, con -t
, se ssh
il cliente muore (ad esempio se inserisci ~.
), la connessione è chiusa e sshd
muore. Di conseguenza, un SIGHUP verrà inviato a tail
.
Ora, fai attenzione che usando -t
ha effetti collaterali. Ad esempio, con le impostazioni predefinite del terminale, \n
i caratteri vengono convertiti in \r\n
e più cose possono accadere a seconda del sistema remoto, quindi potresti voler emettere un stty -opost
(per disabilitare la post-elaborazione dell'output) sull'host remoto se tale output non è destinato a un terminale:
$ 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 altro svantaggio dell'utilizzo di -t
/-tt
è che stdout e stderr non sono differenziati sul client. Sia lo stdout che lo stderr del comando remoto verranno scritti in ssh
stdout 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