2013-06-12 3 views
5

Я довольно новичок в Ruby и не могу найти способ получения вывода внешней команды. Мне нужно извлечь значения, возвращаемые командой. Теперь у меня есть что-то вроде этого:Извлечение значения из stdout Open3.popen3 через RegEx и сохранение его

stdin, stdout, stderr, wait_thr = Open3.popen3("#{path}/foobar", configfile) 

if /exit 0/ =~ wait_thr.value.to_s 
    runlog.puts("Foobar exited normally.\n") 
    puts "Test completed." 
    someoutputvalue = stdout.read("TX.*\s+(\d+)\s+") 
    puts "Output value: " + someoutputvalue 
end 

Но я явно не используя правильный метод на стандартный вывод, так как Руби говорит мне, что это не может преобразовать строку в Integer.

Каким будет правильный способ? Я не могу найти нигде в документации методы, доступные для stdout. Использование stout.read Я использую Ruby 1.9.3.

Update

Чтобы быть совершенно ясно, что я пытаюсь прочитать вывод программы, применять регулярное выражение, и сохранить извлеченное значение в переменную для дальнейшего использования.

Так, например, если «TX» так и так: 28 «Я хотел бы получить только« 28 »(я подтвердил, что регулярное выражение соответствует совпадениям, что мне нужно для соответствия, мне просто интересно, как хранить что извлеченное значение в переменной).

+0

Если вы не хотите общаться с процессом и просто прочитать свой вывод, 'capture3' будет более подходящим (и более простой). –

+0

Что нужно сделать, чтобы читать? Я думал, что единственный аргумент, который вы передали, - это то, как далеко в потоке идти? Может быть, он пытается обрабатывать ваш строковый аргумент как целое число байтов? –

+0

@JoePym аргумент - это XML-файл, используемый foobar для запуска, если это ваш вопрос. – Astaar

ответ

13

Вся необходимая информация находится в Popen3 documentation, но вы должны прочитать все это и внимательно ознакомиться с примерами. Вы также можете получить полезную информацию от Process docs.

Может быть, это будет «splain лучше:

require 'open3' 

captured_stdout = '' 
captured_stderr = '' 
exit_status = Open3.popen3(ENV, 'date') {|stdin, stdout, stderr, wait_thr| 
    pid = wait_thr.pid # pid of the started process. 
    stdin.close 
    captured_stdout = stdout.read 
    captured_stderr = stderr.read 
    wait_thr.value # Process::Status object returned. 
} 

puts "STDOUT: " + captured_stdout 
puts "STDERR: " + captured_stderr 
puts "EXIT STATUS: " + (exit_status.success? ? 'succeeded' : 'failed') 

Запуск, что выходы:

STDOUT: Wed Jun 12 07:07:12 MST 2013 
STDERR: 
EXIT STATUS: succeeded 

Things отметить:

  • Часто приходится closestdin потока. Если вызываемое приложение ожидает ввода на STDIN, оно будет зависать, пока оно не увидит поток, а затем продолжит его обработку.
  • stdin, stdout, stderr являются ручками ввода-вывода, поэтому вы должны прочитать IO class documentation, чтобы узнать, какие методы доступны.
  • Вы должны вывести на stdin с помощью puts, print или write и read или gets из stdout и stderr.
  • exit_status не является строкой, это экземпляр класса Process :: Status. Вы можете столкнуться с попыткой разобрать его версию to_s, но не надо. Вместо этого используйте аксессоры, чтобы узнать, что он вернул.
  • Я передал хэш-код ENV, поэтому дочерняя программа имела доступ ко всей среде, которую родитель видел. Это не обязательно делать; Вместо этого вы можете создать уменьшенную среду для ребенка, если вы не хотите, чтобы у нее был доступ ко всему, или вы можете использовать свое представление об окружающей среде, изменяя значения.
  • Код stdout.read("TX.*\s+(\d+)\s+"), размещенный в вопросе, um ... ерунда. Я понятия не имею, откуда у вас это, поскольку ничего подобного не зафиксировано в классе IO Ruby для IO#read или IO.read.

Это проще в использовании capture3, если вам не нужно писать STDIN вызываемого кода:

require 'open3' 

stdout, stderr, exit_status = Open3.capture3('date') 

puts "STDOUT: " + stdout 
puts "STDERR: " + stderr 
puts "EXIT STATUS: " + (exit_status.success? ? 'succeeded' : 'failed') 

Какие выходы:

STDOUT: Wed Jun 12 07:23:23 MST 2013 
STDERR: 
EXIT STATUS: succeeded 

Извлечение значения из строка с использованием регулярного выражения тривиальна и хорошо покрыта Regexp documentation. Начиная с последнего примера кода:

stdout[/^\w+ (\w+ \d+) .+ (\d+)$/] 
puts "Today is: " + [$1, $2].join(' ') 

Какие выходы:

Today is: Jun 12 2013 

Вот используя String.[] метод, который является чрезвычайно гибким.

Альтернативный используют "под названием" захватывает:

/^\w+ (?<mon_day>\w+ \d+) .+ (?<year>\d+)$/ =~ stdout 
puts "Today is: #{ mon_day } #{ year }" 

который выдает то же самое. Недостатком названных захватов является то, что они медленнее для того, что я считаю незначительным.


"TX So and so: 28"[/\d+$/] 
=> "28" 
+0

Но если я просто 'puts stdout.read', он корректно печатает, почему нужно использовать промежуточную переменную (в моем случае регулярное выражение выполняется в блоке, поэтому проблема с пробелом отсутствует)? Как извлечь значение с помощью regex на capture_stdout в вашем примере? – Astaar

+0

Я сохранил его в промежуточной переменной, чтобы показать вам, как получить доступ к этому из-за пределов блока. Если вам не нужно это делать, тогда не делайте этого. И вы должны использовать нормальное регулярное выражение или подстроку для извлечения значения из 'capture_stdout', нет ничего загадочного или волшебного, это строка, содержащая все, что возвращает код. –

+0

Я внимательно прочитал документацию, мой вопрос более общий вокруг Ruby, в основном спрашивая, как сохранить значение, извлеченное из строки, через регулярное выражение, которое не подпадает под документацию Popen3 .. ни документа Regexp, насколько я могу сказать. Пример, который вы дали, уже работает для меня, так как я прочитал документацию. – Astaar

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