从Ruby运行和终止一个外部进程



我想在Ruby(MRI)进程的控制下运行一个外部进程。

有没有办法在Ruby下启动一个长时间/无限期运行的作业,然后通过编程控制其终止?我原以为这会相对容易,但似乎真的很难找到一种方法来做到这一点。

一些不起作用的示例代码:

pid = fork { system "yes > /dev/null" }
sleep 1  # yes is happily running
Process.kill "TERM", pid

如果我把它作为一个Ruby文件来运行,它运行得很愉快。然而,如果我选择pgrep yes,我会看到yes仍在运行。如果Ipkill yes,它会成功消失。KILL信号并不比TERM信号更成功。

如何更改此代码以在后台运行yes,然后允许其终止?

(如果它很重要,我对此表示怀疑,这是macOS上的MRI Ruby 2.3(哈哈)10.11。)

您有正确的想法,但您错过了一件微妙的事情。调用fork会创建一个子进程,但system也会这样做,因为它是作为fork/exec对实现的,所以实际上你杀死了错误的进程。

你可以判断你是否在那里puts pid,看看你试图杀死哪个进程。您试图杀死的进程通常是实际运行的yes进程的PID减去1。

你可能想要的:

pid = fork do
exec "/usr/bin/yes", out: File::NULL
end
sleep 1
Process.kill 'TERM', pid

使用exec时必须非常小心,因为只要有一点点不规则的迹象,Ruby就会创建一个shell进程来执行您的命令,这会引入另一个子进程。杀死它实际上不会杀死yes命令。在这里,我使用了out:选项来抑制STDOUT,而不是依靠> /dev/null技巧来自动接合外壳包装器。

在一些快速测试中,我发现调用exec 'yes'会导致启动一个中间shell,但指定完整路径可以避免这种情况。

相关内容

最新更新