在Ruby中获取system()调用的输出

本文翻译自:Getting output of system() calls in Ruby

如果我在Ruby中使用Kernel#system调用命令,我该如何获得它的输出?

system("ls")

#1楼

参考:https://stackoom.com/question/2tXT/在Ruby中获取system-调用的输出


#2楼

If you need to escape the arguments, in Ruby 1.9 IO.popen also accepts an array: 如果你需要转义参数,在Ruby 1.9 IO.popen也接受一个数组:

p IO.popen(["echo", "it's escaped"]).read

In earlier versions you can use Open3.popen3 : 在早期版本中,您可以使用Open3.popen3

require "open3"

Open3.popen3("echo", "it's escaped") { |i, o| p o.read }

If you also need to pass stdin, this should work in both 1.9 and 1.8: 如果你还需要传递stdin,这应该适用于1.9和1.8:

out = IO.popen("xxd -p", "r+") { |io|
    io.print "xyz"
    io.close_write
    io.read.chomp
}
p out # "78797a"

#3楼

I'd like to expand & clarify chaos's answer a bit. 我想扩大和澄清一下混乱的答案

If you surround your command with backticks, then you don't need to (explicitly) call system() at all. 如果用反引号包围命令,则根本不需要(显式地)调用system()。 The backticks execute the command and return the output as a string. 反引号执行命令并将输出作为字符串返回。 You can then assign the value to a variable like so: 然后,您可以将值分配给变量,如下所示:

output = `ls`
p output

or 要么

printf output # escapes newline chars

#4楼

While using backticks or popen is often what you really want, it doesn't actually answer the question asked. 虽然使用反引号或popen通常是你真正想要的,它实际上并没有回答问题。 There may be valid reasons for capturing system output (maybe for automated testing). 捕获system输出可能有正当理由(可能用于自动化测试)。 A little Googling turned up an answer I thought I would post here for the benefit of others. 一个小小的谷歌搜索出现了一个答案,我想我会在这里发布,以造福他人。

Since I needed this for testing my example uses a block setup to capture the standard output since the actual system call is buried in the code being tested: 由于我需要这个用于测试我的示例使用块设置来捕获标准输出,因为实际的system调用隐藏在被测试的代码中:

require 'tempfile'

def capture_stdout
  stdout = $stdout.dup
  Tempfile.open 'stdout-redirect' do |temp|
    $stdout.reopen temp.path, 'w+'
    yield if block_given?
    $stdout.reopen stdout
    temp.read
  end
end

This method captures any output in the given block using a tempfile to store the actual data. 此方法使用临时文件捕获给定块中的任何输出以存储实际数据。 Example usage: 用法示例:

captured_content = capture_stdout do
  system 'echo foo'
end
puts captured_content

You can replace the system call with anything that internally calls system . 您可以使用内部调用system任何内容替换system调用。 You could also use a similar method to capture stderr if you wanted. 如果需要,您也可以使用类似的方法捕获stderr


#5楼

If you want the output redirected to a file using Kernel#system , you can do modify descriptors like this: 如果您希望使用Kernel#system将输出重定向到文件,则可以执行以下修改描述符:

redirect stdout and stderr to a file(/tmp/log) in append mode: 在追加模式下将stdout和stderr重定向到文件(/ tmp / log):

system('ls -al', :out => ['/tmp/log', 'a'], :err => ['/tmp/log', 'a'])

For a long running command, this will store the output in real time. 对于长时间运行的命令,这将实时存储输出。 You can also, store the output using a IO.pipe and redirect it from Kernel#system. 您还可以使用IO.pipe存储输出,并从Kernel#system重定向它。


#6楼

The straightforward way to do this correctly and securely is to use Open3.capture2() , Open3.capture2e() , or Open3.capture3() . 正确而安全地执行此操作的直接方法是使用Open3.capture2()Open3.capture2e()Open3.capture3()

Using ruby's backticks and its %x alias are NOT SECURE UNDER ANY CIRCUMSTANCES if used with untrusted data. 如果与不受信任的数据一起使用,使用ruby的反引号及其%x别名在任何情况下都不安全 It is DANGEROUS , plain and simple: 危险 ,简单明了:

untrusted = "; date; echo"
out = `echo #{untrusted}`                              # BAD

untrusted = '"; date; echo"'
out = `echo "#{untrusted}"`                            # BAD

untrusted = "'; date; echo'"
out = `echo '#{untrusted}'`                            # BAD

The system function, in contrast, escapes arguments properly if used correctly : 相反, 如果正确使用system函数会正确地转义参数:

ret = system "echo #{untrusted}"                       # BAD
ret = system 'echo', untrusted                         # good

Trouble is, it returns the exit code instead of the output, and capturing the latter is convoluted and messy. 麻烦的是,它返回退出代码而不是输出,捕获后者是错综复杂的。

The best answer in this thread so far mentions Open3, but not the functions that are best suited for the task. 到目前为止,该线程中的最佳答案提到了Open3,但没有提到最适合该任务的函数。 Open3.capture2 , capture2e and capture3 work like system , but returns two or three arguments: Open3.capture2capture2ecapture3system capture3工作,但返回两个或三个参数:

out, err, st = Open3.capture3("echo #{untrusted}")     # BAD
out, err, st = Open3.capture3('echo', untrusted)       # good
out_err, st  = Open3.capture2e('echo', untrusted)      # good
out, st      = Open3.capture2('echo', untrusted)       # good
p st.exitstatus

Another mentions IO.popen() . 另一个提到了IO.popen() The syntax can be clumsy in the sense that it wants an array as input, but it works too: 语法可能是笨拙的,因为它想要一个数组作为输入,但它也有效:

out = IO.popen(['echo', untrusted]).read               # good

For convenience, you can wrap Open3.capture3() in a function, eg: 为方便起见,您可以将Open3.capture3()包装在一个函数中,例如:

#
# Returns stdout on success, false on failure, nil on error
#
def syscall(*cmd)
  begin
    stdout, stderr, status = Open3.capture3(*cmd)
    status.success? && stdout.slice!(0..-(1 + $/.size)) # strip trailing eol
  rescue
  end
end

Example: 例:

p system('foo')
p syscall('foo')
p system('which', 'foo')
p syscall('which', 'foo')
p system('which', 'which')
p syscall('which', 'which')

Yields the following: 产量如下:

nil
nil
false
false
/usr/bin/which         <— stdout from system('which', 'which')
true                   <- p system('which', 'which')
"/usr/bin/which"       <- p syscall('which', 'which')
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值