You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Ruby创建子进程后无法关闭SSH连接的原因及解决办法

SSH关闭时Ruby脚本挂起的原因与解决办法

问题原因

当通过SSH运行Ruby脚本后关闭连接,SSH会话的控制终端会向前台进程组的所有进程发送SIGHUP信号。父进程收到信号后会退出,但fork出的子进程即便用Process.detach处理(避免僵尸进程),仍持有原终端的标准输入、输出、错误文件描述符。此时SSH会话因终端资源被子进程占用,无法正常终止,导致连接挂起,需手动输入~ + RETURN强制退出。

解决办法

1. 让子进程彻底脱离终端(创建守护进程)

在子进程中执行会话分离与IO重定向,使其完全脱离原终端,父进程仍可正常输出:

pid = fork do
  # 成为新会话的领导者,脱离原终端控制
  Process.setsid
  # 关闭并重定向子进程的标准IO
  STDIN.reopen('/dev/null')
  STDOUT.reopen('/dev/null', 'a')
  STDERR.reopen('/dev/null', 'a')
  
  loop do
    sleep 1
  end
end

Process.detach(pid)

2. 仅重定向子进程的IO,保留父进程输出

若无需子进程输出,仅在子进程内部重定向其标准IO,父进程的输出不受影响:

pid = fork do
  # 子进程单独重定向标准IO到/dev/null
  STDIN.reopen('/dev/null')
  STDOUT.reopen('/dev/null', 'w')
  STDERR.reopen('/dev/null', 'w')
  
  loop do
    sleep 1
  end
end

Process.detach(pid)

# 父进程可正常输出到终端
puts "父进程的输出会保留在SSH会话中"

3. 捕获SIGHUP信号,主动终止子进程

如果希望子进程随SSH连接关闭而终止,可在父进程中捕获SIGHUP信号,主动杀掉子进程:

pid = fork do
  loop do
    sleep 1
  end
end

Process.detach(pid)

# 捕获SIGHUP信号,终止子进程后退出父进程
trap('SIGHUP') do
  Process.kill('TERM', pid)
  exit
end

# 保持父进程运行(按需调整)
sleep

内容的提问来源于stack exchange,提问作者sudoremo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 08:15:54