在 shell 脚本中,我执行以下操作:
#!/bin/sh
while true; do ssh -o ExitOnForwardFailure=yes -L 8080:localhost:80 -N server; sleep 1; done &
... rest of the script, which uses the tunnel as made above ...
这保证了隧道始终保持打开状态,因此在连接丢失的情况下会重新打开。这个隧道在主脚本的其他部分用到了,这里不再赘述。这些部分可以处理一个不起作用的隧道,它们只是稍后重试。
当主脚本死亡时,例如由于SIGTERM
or SIGINT
,我希望该while
循环也停止。主脚本死后无需保持该隧道打开。
在 shell 脚本中执行此操作的常用方法是什么?请注意,我想要两件事:
- 防止重新执行
ssh
命令 ssh
尽快停止并断开当前正在进行的会话
我不确定如何在 shell 脚本中执行所有这些操作。
请注意,我目前在 plain 工作,但如果需要sh
我可以继续工作。bash
一种有点通用的方法。
诀窍是脚本运行子进程(这里
foo
还有其他进程),进程组 ID (PGID) 等于 shell 的 PID。这会传播给孙子等。shell 本身也在这个进程组中。有例外(交互式 shell 中的作业,timeout
)所以这并不像您想要的那样普遍,但在非交互式脚本中仍然使用foo
being或类似的简单命令,该方法应该有效。ssh
kill
带有否定参数的向整个进程组发送信号。但有一个警告:可能的竞争条件。通常
foo
在子外壳接收并处理信号之前可能会被杀死。如果延迟足够长(无论出于何种原因),foo
则可能会在完成其工作sleep 1
后产生新的(特别是如果没有) 。kill
考虑这种改进:这里的陷阱只是为了让主 shell 优雅地退出而不打印
Terminated
到控制台。不是任何后台进程的通用方法,但通常是
ssh
类似场景中的有用方法。使用
autossh
。从它的手册:所以:
请注意,如果无法首先建立隧道,您将不会收到通知。由于这也可能是您原始方法中的一个缺陷,因此我不会在这里解决这个问题。