2013-08-30 2 views
2

Я пытаюсь запустить сценарий оболочки и захватить PID, STDERR, STDOUT и статус выхода оболочки.Использование Ruby 1.8.7, могу ли я выполнить shell и захватить PID, STDOUT, STDERR, статус?

Я использую Ruby 1.8.7, поэтому Open3 не имеет способа получить PID. Я пробовал использовать open4 gem, но, к сожалению, несколько скриптов висели во время процесса записи, который отлично работает при ручном запуске.

Я хотел бы найти альтернативу. Ваше руководство будет высоко оценено!

+0

Вы получаете текущий PID в Ruby с Process.pid. Дайте мне знать, если это поможет – Raghu

+0

Спасибо Raghu, я ищу PID для каждого процесса оболочки, порожденного, а не PID текущего процесса, извините Если мое письмо вводит вас в заблуждение. – Jay

+0

Можете ли вы опубликовать некоторый пример кода, чтобы мы могли попробовать воспроизвести проблему? – iblue

ответ

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 и имеет дело с тремя ручками, то вы можете получить PID и выполнить то, что делает open3.

Обязательно закройте свои дескрипторы файлов после! Урожайная версия этого, которая будет очищаться после этого, вероятно, будет иметь больше смысла.

+0

В качестве примечания, причина, по которой у меня есть процедура «closeOtherFDs» для поиска и закрытия всех объектов stdin/stdout/stderr у детей, заключается в том, что я был нерестами из 100 процессов, и у меня не хватало дескрипторов файлов.Если вы только порождаете несколько, то вы, вероятно, можете извлечь этот код. –

+0

А также я понял, что код, который я вставил, закрывал stderr, b ut вы должны быть в состоянии выяснить, как использовать tmpfifo для этого. –

+0

Спасибо @David Ljung Madison за то, что вы помогли мне, я просто хочу, чтобы это было просто, поскольку у меня есть тысячи процессов, которые будут созданы. Во всяком случае, я использовал обратный ход выполнения для перемещения вывода на основе состояния выхода. Еще раз спасибо!! – Jay

 Смежные вопросы

  • Нет связанных вопросов^_^