我的计划是编写一个脚本来调试远程 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+c或Ctrl+ ?z
在这里,您将 的标准输入重定向ssh
。该工具从此处的文档中读取,而不是从 tty 中读取。即使本地 tty 配置为不发送 SIGINT,您键入^C
的Ctrl+c也永远无法到达远程端,因为ssh
根本不从 tty 读取。如果^C
确实位于此处的文档中,那么它可以在远程端触发 SIGINT。(注意,我不是说^
后面跟着C
,它必须是单字节字符我们表示 ^C
,ASCII ETX,0x03。)比较技巧这个答案我通过打印相应的字符来发送Ctrl+c和Ctrl+ 。d
由于您的本地ssh
不从 tty 读取,因此它首先没有理由重新配置它。您的Ctrl+c导致 SIGINT本地并终止ssh
。一般来说远程进程(如start server in debug mode
)可能能够幸存下来。
如果你想要Ctrl+c你类型要访问服务器,您绝对希望ssh
从终端读取。这意味着您不能使用此处的文档。
至少有两种方法:
将 shell 代码存储在远程端的脚本中,直接通过 ssh 进入交互式 shell(其中Ctrl+ c“简单”按预期工作)并运行该脚本。
或者将 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那里。