Come terminare in remoto chiamato "tail -f" quando la connessione è chiusa?


24

Ho appena notato che se eseguo ssh user@remote_host tail -f /some/file, tail -f /some/filecontinua a funzionare su remote_host anche se la connessione ssh è chiusa!

Quindi, dopo diverse connessioni e disconnessioni, il numero di corse tail -f /some/fileaumenta. Come terminare effettivamente tail -fquando la connessione ssh è chiusa?

Risposte:


33

Nel

ssh host tail -f file

Il sshclient si connette al sshdserver su hostuna connessione TCP. sshdviene eseguito tail -fcon il suo stdout reindirizzato a una pipe. sshdlegge ciò che proviene dall'altra estremità della pipe e lo incapsula nel protocollo sshd da inviare al sshclient. (con rshd, tailstdout sarebbe stato il socket direttamente, ma sshdaggiunge la crittografia ed è in grado di multiplexare diversi flussi (come per il reindirizzamento port / agent / X11 / tunnel, stderr) su una singola connessione TCP, quindi deve ricorrere alle pipe).

Quando si preme CTRL-C, un SIGINT viene inviato al sshclient. Questo fa sshmorire. Alla morte la connessione TCP viene chiusa. E quindi, anche host, sshdmuore. tailnon viene ucciso, ma il suo stdout è ora una pipe senza lettore dall'altra parte. Quindi, la prossima volta che scrive qualcosa sul suo stdout, riceverà un SIGPIPE e morirà.

Nel:

ssh -t host 'tail -f file'

È la stessa cosa, tranne che invece di essere con una pipe, la comunicazione tra sshde tailavviene tramite uno pseudo-terminale. tailLo stdout è uno pseudo-terminale slave (come /dev/pts/12) e qualunque cosa tailscriva readsul lato master (possibilmente modificato dalla disciplina tty line) da sshde inviato incapsulato al sshclient.

Sul lato client, con -t, sshmette il terminale in rawmodalità. In particolare, ciò disabilita la modalità canonica terminale e la gestione del segnale terminale.

Quindi, quando si preme Ctrl+C, invece della disciplina della linea terminale del client che invia un SIGINT al sshlavoro, che invia semplicemente il ^Ccarattere sulla connessione sshde lo sshdscrive ^Csul lato principale del terminale remoto. E la disciplina di linea del terminale remoto invia un SIGINTa tail. tailquindi muore, sshdesce e chiude la connessione e sshtermina (se non è comunque occupato con il port forwarding o altro).

Inoltre, con -t, se il sshclient muore (ad esempio se si immette ~.), la connessione viene chiusa e sshdmuore. Di conseguenza, verrà inviato un SIGHUP tail.

Ora, attenzione che l'utilizzo -tha effetti collaterali. Ad esempio, con le impostazioni predefinite del terminale, i \ncaratteri vengono convertiti in \r\ne potrebbero accadere altre cose a seconda del sistema remoto, quindi potresti voler emettere un stty -opost(per disabilitare la post-elaborazione dell'output) sull'host remoto se quell'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'uso di -t/ -ttè che stdout e stderr non sono differenziati sul client. Sia lo stdout che lo stderr del comando remoto verranno scritti nello sshstdout del 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

Grazie mille per una spiegazione così dettagliata! Vorrei poter accettare due risposte ..
Dmitry Frank,

"con -t, se il sshclient muore (ad esempio, se si inserisce ~.)" Che cos'è di ~.nuovo?
X-yuri,

1
@ x-yuri, ~.è la sequenza di escape immessa per disconnettere il client. Vedi man sshper i dettagli.
Stéphane Chazelas,

11

È necessario l'allocazione dei terminali sul lato remoto:

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

o anche

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

1
Grazie, entrambi -to -ttfunziona. Ma non riesco ancora a capire il vero motivo di ciò: diciamo, quando chiamo la shell da remoto e chiudo la connessione, la shell viene terminata. Ma tail -fnon lo è. Naturalmente ho già letto -tdell'opzione in man ssh, ma non è stato di grande aiuto. Sembra che non capisca alcuni generici, e sarei felice se suggerissi alcuni documenti da leggere al riguardo, o probabilmente lo spieghi tu stesso. Grazie!
Dmitry Frank,

2
@DmitryFrank La mia comprensione è questa: se la connessione si interrompe, sshdinvia a SIGHUP. Ma dove non ci sono terminali non ci possono essere interruzioni di connessione ai terminali ...
Hauke ​​Laging,

Grazie, leggerò SIGHUPe altri segnali, ancora non ne so quasi nulla.
Dmitry Frank,

fyi: ho appena provato a correre tail -f, poi l'ho aperto htope inviato SIGHUPad esso (premendo F9-> 1-> Enter), ed tail -fè terminato! Quindi, la ragione dovrebbe essere diversa ...
Dmitry Frank,

3
@DmitryFrank Hai frainteso il problema. Il problema non è che tailnon reagirebbe a SIGHUP. Il problema è che SIGHUP** non viene inviato` tailsenza uno pseudo terminale. Si può vedere che attaccando stracea tailin entrambi i casi.
Hauke ​​Laging,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.