如何获取外部命令的输出并从中提取值?
我有这样的事情:
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
我没有在stdout上使用正确的方法,因为Ruby告诉我它不能将String转换为Integer。
例如,如果输出是
"TX So and so: 28"
我想只获得“28
”。我验证了上面的正则表达式匹配我需要匹配的内容,我只是想知道如何将该提取的值存储在变量中。
这样做的正确方法是什么?我在文档中找不到stdout可用的方法。我正在使用Ruby 1.9.3中的stout.read
。
答案 0 :(得分:14)
所需的所有信息都在Popen3 documentation中,但您必须仔细阅读并仔细查看示例。您也可以从Process docs收集有用的信息。
也许这会'更好地摒弃它:
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
注意事项:
close
stdin
个流。如果被调用的应用程序期望在STDIN上输入它将挂起,直到它看到流关闭,然后将继续其处理。stdin
,stdout
,stderr
是IO句柄,因此您必须阅读IO class documentation以找出可用的方法。stdin
,puts
或print
,write
或read
从gets
输出到stdout
和stderr
。 exit_status
不是字符串,它是Process :: Status类的实例。你可以搞砸尝试从to_s
版本解析,但不要。而是使用访问器来查看它返回的内容。ENV
哈希,因此子程序可以访问父看到的整个环境。没有必要这样做;相反,如果您不希望孩子访问所有内容,您可以为孩子创建一个简化的环境,或者您可以通过更改值来混淆其对环境的看法。stdout.read("TX.*\s+(\d+)\s+")
是,嗯......废话。我不知道你在哪里得到它,因为Ruby的IO类IO#read或IO.read中没有记录这一点。如果您不需要写入被调用代码的STDIN,则更容易使用capture3
:
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"