【问题标题】:Using Ruby 1.8.7, can I execute shell and capture PID, STDOUT, STDERR, status?使用 Ruby 1.8.7,我可以执行 shell 并捕获 PID、STDOUT、STDERR、状态吗?
【发布时间】:2023-03-07 16:01:01
【问题描述】:

我正在尝试运行一个 shell 脚本并捕获 PID、STDERR、STDOUT 和 shell 的退出状态。

我使用的是 Ruby 1.8.7,因此 Open3 无法获取 PID。我尝试使用 open4 gem,但不幸的是,在写入过程中挂起了一些脚本,手动运行时运行良好。

我想找到一个替代方案。非常感谢您的指导!

【问题讨论】:

  • 您在 Ruby 中使用 Process.pid 获取当前 PID。让我知道这是否有帮助
  • 感谢 Raghu,我正在寻找生成的每个 shell 进程的 PID,而不是当前进程的 PID,对不起,如果我的文字误导了你..
  • 您能否发布一些示例代码,以便我们尝试重现该问题?
  • 感谢您的回复@iblue,我不打算分享内部信息很少的外壳,对此感到抱歉.. 我需要的是通过 ruby​​ 实现这一目标的替代方案。下面是挂起的 strace “附加进程 32187 - 中断退出 wait4(-1, ”。
  • 如果您不能共享实际代码,请编写一个具有相同问题的示例。使用popen4,您可能需要担心如何处理捕获的IO,如果您不跟上它,具有大量输出的进程可能会阻塞。

标签: ruby shell open4


【解决方案1】:

不幸的是,没有一种简单的方法可以做到这一点。我试过 PTY.spawn 但有时它会执行失败。如果你不能使用 open3,那么你可以使用 FIFO,但它会有点乱。这是我在 1.8.7 上使用的解决方案:

# Avoid each thread having copies of all the other FDs on the fork
def closeOtherFDs
  ObjectSpace.each_object(IO) do |io|
    unless [STDIN, STDOUT, STDERR].include?(io)
      unless(io.closed?)
        begin
          io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
        rescue ::Exception => err
        end
      end
    end
  end
end


# Utilities for fifo method
require 'tempfile'
def tmpfifo
  # Use tempfile just to manage naming and cleanup of the file
  fifo = Tempfile.new('fifo.').path
  File.delete(fifo)
  system("/usr/bin/mkfifo",fifo)
  #puts "GOT: #{fifo} -> #{$?}"
  fifo
end

# fifo homebrew method
def spawnCommand *command
  ipath = tmpfifo
  opath = tmpfifo
  #epath = tmpfifo

  pid = fork do
    #$stdin.reopen(IO.open(IO::sysopen(ipath,Fcntl::O_RDONLY)))
    $stdin.reopen(File.open(ipath,'r'))
    $stdout.reopen(File.open(opath,'w'))
    #$stderr.reopen(File.open(epath,'w'))
    $stderr.close
    closeOtherFDs
    exec(*command)
    exit
  end

  i = open ipath, 'w'
  #i.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) # Doesn't work?  Use closeOtherFDs
  o = open opath, 'r'
  #e = open epath, 'r'
  e = nil
  [o,i,e].each { |p| p.sync = true if p }

  [o,i,e]
end

不,它不干净。但是因为它使用了fork并且自己处理了三个句柄,所以你可以得到PID并完成open3所做的事情。

确保之后关闭您的文件句柄!之后清理的收益版本可能更有意义。

【讨论】:

  • 请注意,我使用“closeOtherFDs”例程来查找和关闭子项中的所有 stdin/stdout/stderr 对象的原因是因为我产生了 100 多个进程并且我用完了文件句柄。如果您只生成几个,那么您可能可以删除该代码。
  • 而且,我刚刚意识到我粘贴的代码正在关闭 stderr,但您应该也能弄清楚如何使用 tmpfifo。
  • 感谢@David Ljung Madison 抽出宝贵时间帮助我,我只想保持简单,因为我有数千个进程要生成。无论如何,我使用了反引号的执行方式来根据退出状态移动输出。再次感谢!!
  • 没问题。不知道为什么我被否决了,有点奇怪,他们无法分享他们对我的解决方案有什么问题,据我所知,即使您决定采取不同的路线,也可以很好地回答您的原始问题. (并随时投票给我的答案!:)
猜你喜欢
  • 2010-12-05
  • 1970-01-01
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 2013-01-12
相关资源
最近更新 更多