运行 并终止来自 Ruby 的外部进程
Running and terminating an external process from Ruby
我想 运行 一个受 Ruby (MRI) 进程控制的外部进程。
有没有办法在 Ruby 下启动 long/infinite 运行ning 作业,然后以编程方式控制其终止?我认为这会相对容易,但似乎真的很难找到一种方法来做到这一点。
一些示例代码,不起作用:
pid = fork { system "yes > /dev/null" }
sleep 1 # yes is happily running
Process.kill "TERM", pid
如果我 运行 这是一个 Ruby 文件,它 运行 很高兴。但是,如果我然后 pgrep yes
我看到 yes
仍然是 运行ning。如果我 pkill yes
它成功消失了。 KILL
信号并不比 TERM
信号更成功。
我如何在后台将此代码更改为 运行 yes
然后允许其终止?
(以防万一,我对此表示怀疑,这是在 macOS(哈哈)10.11 上使用 MRI Ruby 2.3。)
你的想法是正确的,但你错过了一个微妙的东西。调用 fork
会创建一个子进程,但 system
也会执行此操作,因为它是作为 fork
/exec
对实现的,因此实际上您正在终止错误的进程。
您可以判断您是否 puts pid
在那里查看您要杀死的进程。您要杀死的通常是 yes
进程的 PID,实际上是 运行 减一。
您可能想要的:
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
技巧,它会自动使用 shell 包装器。
在一些快速测试中,我发现调用 exec 'yes'
会导致中间 shell 启动,但指定完整路径可以避免这种情况。
我想 运行 一个受 Ruby (MRI) 进程控制的外部进程。
有没有办法在 Ruby 下启动 long/infinite 运行ning 作业,然后以编程方式控制其终止?我认为这会相对容易,但似乎真的很难找到一种方法来做到这一点。
一些示例代码,不起作用:
pid = fork { system "yes > /dev/null" }
sleep 1 # yes is happily running
Process.kill "TERM", pid
如果我 运行 这是一个 Ruby 文件,它 运行 很高兴。但是,如果我然后 pgrep yes
我看到 yes
仍然是 运行ning。如果我 pkill yes
它成功消失了。 KILL
信号并不比 TERM
信号更成功。
我如何在后台将此代码更改为 运行 yes
然后允许其终止?
(以防万一,我对此表示怀疑,这是在 macOS(哈哈)10.11 上使用 MRI Ruby 2.3。)
你的想法是正确的,但你错过了一个微妙的东西。调用 fork
会创建一个子进程,但 system
也会执行此操作,因为它是作为 fork
/exec
对实现的,因此实际上您正在终止错误的进程。
您可以判断您是否 puts pid
在那里查看您要杀死的进程。您要杀死的通常是 yes
进程的 PID,实际上是 运行 减一。
您可能想要的:
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
技巧,它会自动使用 shell 包装器。
在一些快速测试中,我发现调用 exec 'yes'
会导致中间 shell 启动,但指定完整路径可以避免这种情况。