用Ruby关闭使用PTY.spawn打开的虚拟shell

3
在一个Ruby脚本中,我启动了更多的虚拟shell,每个都由一个shell管理器对象管理,如下所示:
@shell = PTY.spawn 'env PS1="\w>" TERM=dumb COLUMNS=63 LINES=21 sh -i'

在稍后的某个时间点,我想销毁此实例并杀死相关的 shell 进程。可惜,我无法使任何东西正常工作。以下是我尝试过的内容,按照可能性排序:
- 什么都不做,期望在管理对象被销毁时关闭 shell 进程。 - 使用 kill 命令杀死运行在 shell 上的所有进程(这个可以),然后使用 system("kill #{@shell[2]") 来杀死 shell 本身。这没有任何效果。 - 在上述命令中使用 -9。这会使 shell 进程变成僵尸进程。
当 ruby 程序退出时,所有 shell 都会被关闭,但我想在程序继续运行的同时杀死它们。有人遇到过类似的情况吗?
1个回答

5

问题出在僵尸进程上。是的,真的。

所有类Unix内核都会一直保留进程,直到有人等待它结束。这是为了跟踪PID、退出状态和其他一些信息。这些进程被称为僵尸进程,在ps(1)列表中显示为Z状态。你无法杀死它们,因为它们已经死亡。只有当你等待它们时,它们才会消失。

所以,以下是如何清理您的@shell对象:

@shell[0].close
@shell[1].close
begin
  Process.wait @shell[2]
rescue PTY::ChildExited
end

如果你的高级层面过于宽泛地捕获异常,那么你可能不需要救援块。(哎,就像我的irb一样。)

顺便说一下,当Ruby程序退出时,你的进程最终消失的原因是因为这个僵尸进程也变成了孤儿(没有父进程),然后shell或init(8)将最终等待所有孤儿进程。


2
至少Unix开发人员将凭借他们等待所有死亡孤立的僵尸shell消失的经验为世界末日做好了准备。 - Kai
1
谢谢!在 kill 后加上 Process.wait(@shell[2]) 就可以让它工作了。 - mirceapricop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接