【问题标题】:How to wait for process to finish using IO.popen?如何使用 IO.popen 等待进程完成?
【发布时间】:2009-08-01 19:58:15
【问题描述】:

我在 Ruby 中使用IO.popen 在循环中运行一系列命令行命令。然后我需要在循环之外运行另一个命令。直到循环中的所有命令都终止后,循环外的命令才能运行。

如何让程序等待这种情况发生?目前最后的命令运行得太快了。

一个例子:

for foo in bar
    IO.popen(cmd_foo)
end
IO.popen(another_cmd)

所以所有cmd_foos 都需要在another_cmd 运行之前返回。

【问题讨论】:

    标签: ruby linux command-line


    【解决方案1】:

    使用区块形式,阅读全部内容:

    IO.popen "cmd" do |io|
      # 1 array
      io.readlines
    
      # alternative, 1 big String
      io.read
    
      # or, if you have to do something with the output
      io.each do |line|
        puts line
      end
    
      # if you just want to ignore the output, I'd do
      io.each {||}
    end
    

    如果您不读取输出,则可能是进程阻塞,因为连接另一个进程和您的进程的管道已满,没有人从中读取。

    【讨论】:

    • IO.popen('cmd').close 在丢弃标准输出时会起作用吗?文档说它设置了$?(因此等待),但我不清楚它也会丢弃所有标准输出而不阻塞。
    • “丢弃标准输出”到底是什么意思?您显示的代码不会丢弃任何内容。如果你只想执行一些东西而不做任何特殊的输出 system() 更合适,
    • 通过“丢弃标准输出”我的意思是“读取输出”,这个答案说可能需要防止阻塞。
    • 但目标是什么?您真的要丢弃输出吗?然后你必须阅读它并忽略它。在这种情况下,system() 不是一个好的选择,除非您将 stdout 重定向到 /dev/null。通常必须读取 stdout 和 stderr ,否则您可能会阻塞进程。
    • 先看标准库。它实际上非常有用。
    【解决方案2】:

    显然canonical way 这样做是:

     Process.wait(popened_io.pid)
    

    【讨论】:

    • 这个答案是最正确的。没有副作用(就像 io.read 一样),而且它的作用非常明显。
    • 看起来.close 也在等待,因为它设置了$?,并且在调用.close 后在管道的pid 上调用Process.wait 会产生ECHILD 错误。
    • 看起来#close 基本上关闭了“IO 和进程”,所以是的,如果你不介意你的 IO 被关闭 github.com/ruby/ruby/blob/…
    【解决方案3】:

    我认为您需要将循环内IO.popen 调用的结果分配给变量,并继续对它们调用read(),直到eof() 全部变为真。

    那么你就知道所有的程序都执行完了,你就可以开始another_cmd了。

    【讨论】:

    • 作为补充说明:使用块形式的 IO 方法通常更安全。此外,在 1.9 中,您获得了额外的稳健性,因为块变量具有不同的作用域,这可以防止在块之外修改相同命名的变量(并且您会收到警告)。
    【解决方案4】:
    for foo in bar
      out = IO.popen(cmd_foo)
      out.readlines
    end
    IO.popen(another_cmd)
    

    将输出读取到变量然后调用out.readlines 做到了。我认为out.readlines 必须等待进程结束才能返回。

    感谢 Andrew Y 为我指明了正确的方向。

    【讨论】:

    • 我尝试了完全相同的事情并最终得到了僵尸(已失效),所以不理想
    • 它丢失了。关闭
    【解决方案5】:

    我建议你使用Thread.join来同步最后一次popen调用:

    t = Thread.new do
        for foo in bar
           IO.popen(cmd_foo)
        end
    end
    
    t.join
    
    IO.popen(another_cmd)
    

    【讨论】:

      【解决方案6】:

      你需要popen的输出吗?如果没有,您要使用Kernel#system 还是其他命令?

      【讨论】:

        猜你喜欢
        • 2011-07-11
        • 1970-01-01
        • 2012-03-16
        • 2010-11-06
        • 2011-11-09
        • 2012-07-27
        相关资源
        最近更新 更多