如何防止 CTRL+C 中断 ssh 连接?

如何防止 CTRL+C 中断 ssh 连接?

当我想停止时,tail -f我按CTRL+C并返回提示。但是当我运行 ssh 连接时,CTRL+C会中断连接。 (描述的标志的含义这里

ssh -t svf "cd ~/w/logs; tail -f some_file.log; exec $SHELL -l"

帖子没有描述如何防止远程 shell 退出ssh -t remotehost command args ...

如何使用+停止命令(在本例中tail -f)并且不中断 ssh 连接?CTRLC

答案1

ssh -t svf "cd ~/w/logs; tail -f some_file.log; exec $SHELL -l"

-t表示本地 tty 线路规则设置为原始(直通)模式,并在远程端创建伪 tty。

该伪终端将获得默认设置,这在大多数系统上意味着例如一个^C字符将导致 SIGINT 被发送到该伪终端的前台进程组。

在这里,当您ssh使用命令时,sshd会运行login-shell-of-the-remote-user -c that-command.这是一个非交互式 shell,因此它不执行作业控制。

特别是,该 shell 像它运行的每个命令一样将在同一进程组中运行,该进程组是终端的前台进程组。

不过, shell $SHELL -l(请注意,它$SHELL在本地计算机上扩展,这可能不是您想要的)将是一个交互式 shell(因为它的调用没有,-c并且它的 stdin 是终端设备),因此将在不同的进程组中运行命令(管道)并根据需要使它们成为或不成为终端的前台进程组。

在这里,为了使其仅tail -f接收 SIGINT,或者至少仅杀死它而不是 shell,您有多个选项,具体取决于远程用户的登录 shell。

如果远程用户的登录 shell 是bashyash,您可以执行以下操作:

ssh -t svf 'set -m; cd ~/w/logs && tail -f some_file.log; exec "$SHELL" -l'

-m选项启用作业控制。这告诉 shell 在单独的进程组中运行管道(如交互式 shell),并且(对于bashyash,通常不适用于所有其他 shell)在前台运行的管道的进程组将成为终端设备的前台进程组(因此例如,它们得到SIGINTon^CSIGTSTPon ),而在后台启动的则不是(因此它们被禁止(接收 SIGTTIN)从终端读取)。^Z

这种方式tail -f将在其自己的进程组中运行,该进程组将是前台进程组。如果在tail运行时键入 CTRL+C ,则只会tail收到 SIGINT。

如果您知道 shell 与 Bourne 类似,另一种选择是为 SIGINT 设置处理程序:

ssh -t svf 'trap : INT; cd ~/w/logs && tail -f some_file.log; exec "$SHELL" -l'

在这里,我们正在配置 shell,以便它:在收到 SIGINT 时执行(无操作)命令。子进程将继承该处理程序,但在执行命令时,处理程序将重置为默认值(终止进程)。

所以现在,在运行时按 CTRL-C tail,shell 和tail都会收到 SIGINT,但只有 tail 会因此而死亡,并且 shell 将继续执行"$SHELL" -l.

如果您知道bashyash可以在远程主机上使用(并且远程 shell 类似于 Bourne 或 csh),您还可以执行以下操作:

ssh -t svf 'cd ~/w/logs && bash -c "set -m; tail -f some_file.log"; exec "$SHELL" -l'

我们bash显式调用 shell 并打开该-m选项,以便它将tail在其自己的前台进程组中启动,并且只有它才会像第一个解决方案一样接收 SIGINT。

使用bash-4.3或 以上,您可以将 替换bash -c "set -m;bash -mc "。这不适用于旧版本,它会忽略传递给解释器的-m(and -i) 选项(bash如果与-c.

答案2

为了防止CTRL+C断开连接,它应该是交互式的。

这是通过 实现的bash -i。所以我可以运行:

ssh -t svf 'cd ~/w/logs; bash -i tail -f some_file.log; exec $SHELL -l'

但这个原因问题。要解决它,您可以创建解决方法。在远程计算机上创建脚本来运行命令(注意-i标志。这很重要。如果您需要与正常登录时相同的 ENV,您-l也可以添加标志):

$ cat ~/cmd 
#!/bin/bash -i
cmd="$*"
eval $cmd

然后我将命令修改为:

ssh -t svf 'cd ~/w/logs; ~/cmd tail -f some_file.log; exec $SHELL -l'

现在我很高兴并且可以CTRL+C何时tail -f运行。由于交互性,bash -issh 连接不会中断,并且exec $SHELL -l在调用热键后会执行命令。

重要的提示:您应该使用 ' 而不是 " 在远程端而不是本地扩展 $SHELL。感谢 Stéphane Chazelas

相关内容