连接关闭时如何远程终止调用“tail -f”?

连接关闭时如何远程终止调用“tail -f”?

我只是注意到,如果我执行ssh user@remote_host tail -f /some/file,那么tail -f /some/file即使 ssh 连接关闭,也会在remote_host上继续运行!

因此,在多次连接和断开连接之后,运行次数tail -f /some/file会增加。tail -f当 ssh 连接关闭时如何实际终止?

答案1

ssh host tail -f file

客户端通过 TCP 连接ssh连接到sshd服务器。运行时其标准输出重定向到管道。读取来自管道另一端的内容并将其封装在 sshd 协议中以发送到客户端。 (使用 时,stdout 会直接是套接字,但增加了加密,并且能够在单个 TCP 连接上复用多个流(例如端口/代理/X11/隧道重定向、stderr),因此必须求助于管道)。hostsshdtail -fsshdsshrshdtailsshd

当您按 CTRL-C 时,SIGINT 会发送到ssh客户端。那会导致ssh死亡。一旦死亡,TCP 连接就会关闭。因此, onhostsshd死亡。tail没有被杀死,但它的标准输出现在是一个管道,另一端没有读取器。因此,下次它向其标准输出写入内容时,它将收到 SIGPIPE 并死亡(尽管最新版本的 GNUtail监视器会发现其标准输出变成损坏的管道并在这种情况下立即退出,另请参阅这个相关问题的答案了解如何检测破损的管道)。

在:

ssh -t host 'tail -f file'

两者是相同的,只是 和 之间的通信不是通过管道,sshd而是tail通过伪终端进行。tail的 stdout 是一个从属伪终端(如/dev/pts/12),并且主端上tail的任何写入(可能由 tty 线路规则修改)并封装发送到客户端。readsshdssh

在客户端,使用-tssh将终端置于raw模式。特别是,这会禁用终端规范模式和终端信号处理。

因此,当您按 时Ctrl+C,客户端的终端线路规则不会向作业发送 SIGINT ssh,而是^C通过连接将字符发送到远程终端的主端sshd并将sshd其写入。^C远程终端的线路纪律发送一个SIGINTto tailtail然后死亡,sshd退出并关闭连接并ssh终止(如果它不是仍然忙于端口转发或其他)。

另外,使用 时-t,如果ssh客户端终止(例如,如果您输入~.),连接将关闭并sshd终止。结果,一个 SIGHUP 将被发送到tail.

现在,请注意使用-t有副作用。例如,使用默认终端设置,\n字符会被转换为\r\n,并且可能会发生更多情况,具体取决于远程系统,因此stty -opost如果该输出不适合在远程主机上发出(以禁用输出后处理)一个终端:

$ 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

-t使用/的另一个缺点-tt是 stdout 和 stderr 在客户端上不区分。远程命令的 stdout 和 stderr 都将写入ssh客户端的 stdout:

$ ssh localhost ls /x  | wc -l
ls: cannot access /x: No such file or directory
0
$ ssh -t localhost ls /x | wc -l
1

答案2

您需要在远程端分配终端:

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

甚至

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

相关内容