2

シェル スクリプトを実行して、PID、STDERR、STDOUT、およびシェルの終了ステータスを取得しようとしています。

Ruby 1.8.7 を使用しているため、Open3 には PID を取得する方法がありません。open4 gem を使用してみましたが、残念ながら書き込みプロセス中にいくつかのスクリプトがハングしました。手動で実行すると問題なく動作します。

代替案を見つけたいと思います。ご指導よろしくお願いします!

4

1 に答える 1

0

残念ながら、これを行う簡単な方法はありません。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 を使用して 3 つのハンドル自体を処理するため、PID を取得して open3 が行うことを実行できます。

その後、必ずファイルハンドルを閉じてください! 後でクリーンアップするこれの生成バージョンは、おそらくより理にかなっています。

于 2013-10-16T10:35:38.390 に答える