fork问题,返回值并返回提示

时间:2016-06-12 15:38:45

标签: ruby

下面的代码有两个问题。任何人都可以帮忙吗?

  1. 如何返回[captured_stdout,captured_stderr]的值?

  2. 当在popen3中使用puts时,ruby在打印后不会返回提示。 我该如何解决这个问题?

  3. == code

    #!/bin/env ruby
    
    require 'open3'
    require 'etc'
    
    def as_user(user, &block)
      u = Etc.getpwnam(user)
      Process.fork do
          Process.uid = u.uid
          block.call(user)
      end
    end
    
    def run_cmd(cmd)
      as_user "oracle" do |user|
        puts("In block as #{user} (uid=#{Process.uid}), pid is #{Process.pid}")
        Open3.popen3(cmd) do |i,o,e,wait_thr|
            stdout = o.read
            stderr = e.read
            [stdout, stderr]
        end
      end
    end
    
    output = run_cmd("/bin/date")
    puts output
    

    ==输出

    [root@test]# ./x2.rb
    24810
    In block as oracle (uid=1001), pid is 24810
    [root@test]#
    

1 个答案:

答案 0 :(得分:0)

我不认为你应该从方法返回,直到popen方法调用(包括你指定的块)完成。如果这是真的,那么您需要在调用popen之前声明这些返回变量,然后仅在popen完成后返回它们。像这样:

def run_cmd(cmd)
  as_user "user1" do |user|
    puts("In block as #{user} (uid=#{Process.uid}), pid is #{Process.pid}")

    captured_stdout = captured_stderr = nil  # just to declare them

    Open3.popen3(cmd) do |i,o,e,wait_tnr|
       captured_stdout = o.read
       captured_stderr = e.read

       i.close
       o.close
       e.close

    end
    [captured_stdout, captured_stderr]
  end
end

顺便问一下,你确定要使用Ruby 1.8吗?它现在非常古老,并且在很长一段时间内都没有得到支持。

考虑到这一点,删除本地captured_变量和close调用可以大大简化:

def run_cmd(cmd)
  as_user "user1" do |user|
    puts("In block as #{user} (uid=#{Process.uid}), pid is #{Process.pid}")
    Open3.popen3(cmd) { |i,o,e,wait_tnr| [o.read, e.read] }
  end
end

为了加强这一点,您可能希望添加一个线程连接,以便在命令关闭其stdout然后需要运行一段时间之后,它会有时间完成其工作:

def run_cmd(cmd)
  as_user "user1" do |user|
    puts("In block as #{user} (uid=#{Process.uid}), pid is #{Process.pid}")
    Open3.popen3(cmd) do |i,o,e,wait_tnr|
      stdout = o.read
      stderr = e.read
      wait_thr.join
      [stdout, stderr]
    end
  end
end