ssh 中带有陷阱的 Unix 脚本

ssh 中带有陷阱的 Unix 脚本

我的计划是编写一个脚本来调试远程 Web 服务器。

由于防火墙阻止了调试端口,我需要通过 ssh 将远程端口转发到本地计算机。这部分工作正常。

在调试模式下运行服务器的命令会阻塞终端。因此,当我按下 CTRL C 时,服务器应该停止。但是,我希望在完成调试后以正常模式重新启动服务器。因此,我添加了一个 trap 命令。

这是我目前的方法:

ssh -tt my.server -L 8001:localhost:8000 <<'ENDSSH'

trap 'start server as service in normal mode' 2

stop server
start server in debug mode

ENDSSH

但是,当我按下 CTRL C 时,ssh 连接终止,并且陷阱内的命令未执行。

这里有完整的脚本新手。需要帮助。

答案1

通常ssh能够“中继” Ctrl+c并在远端引起 SIGINT,当发生以下情况时:

  • ssh请求并获取远程端的 tty,
  • ssh配置本地 tty,因此Ctrl+c并不特殊,并从中读取。

在这种情况下Ctrl+c不会让本地终端驱动程序向前台进程组(即ssh)发送 SIGINT。ssh将读取^C 特点并将其像其他字符一样传递给服务器。远程终端驱动程序将获取该字符并引发 SIGINT在服务器上(或不,取决于其自身的设置)。请参阅如何通过 SSH 发送Ctrl+cCtrl+ ?z

在这里,您将 的标准输入重定向ssh。该工具从此处的文档中读取,而不是从 tty 中读取。即使本地 tty 配置为不发送 SIGINT,您键入^CCtrl+c也永远无法到达远程端,因为ssh根本不从 tty 读取。如果^C确实位于此处的文档中,那么它可以在远程端触发 SIGINT。(注意,我不是说^后面跟着C,它必须是单字节字符我们表示 ^C,ASCII ETX,0x03。)比较技巧这个答案我通过打印相应的字符来发送Ctrl+cCtrl+ 。d

由于您的本地ssh不从 tty 读取,因此它首先没有理由重新配置它。您的Ctrl+c导致 SIGINT本地并终止ssh一般来说远程进程(如start server in debug mode)可能能够幸存下来。

如果你想要Ctrl+c类型要访问服务器,您绝对希望ssh从终端读取。这意味着您不能使用此处的文档。

至少有两种方法:

  1. 将 shell 代码存储在远程端的脚本中,直接通过 ssh 进入交互式 shell(其中Ctrl+ c“简单”按预期工作)并运行该脚本。

  2. 或者将 shell 代码作为参数传递给ssh,而不是通过其 stdin。此方法不会自动在远程端分配 tty,但您需要它,因此使用-t-tt也可以)。

    例子:

    ssh -t my.server -L 8001:localhost:8000 '
    trap "start server as service in normal mode" INT
    stop server
    start server in debug mode
    '
    

    请注意,示例中的整个 shell 代码都是单引号,看起来很简单,但如果您需要在远程端使用实际的单引号,那么就会变得复杂;请参阅如何方便地在 Bash 中单引号或转义整个命令行?

在任何这些情况下,您的本地ssh都将使用本地终端,以使Ctrl+c到达远程端并导致 SIGINT那里

相关内容