是否有自动方式在Ruby中进行shell管道?我正在尝试将以下shell代码转换为Ruby:
a | b | c... > ...
但到目前为止我找到的唯一解决方案是自己进行缓冲管理(简化,未经测试,希望它能得到我的意思):
a = IO.popen('a')
b = IO.popen('b', 'w+')
Thread.new(a, b) { |in, out|
out.write(in.readpartial(4096)) until in.eof?
out.close_write
}
# deal with b.read...
我想我正在寻找的是告诉popen使用现有流而不是创建新流的方法?或者,IO#merge方法将输出连接到b的输入?当滤波器数量增加时,我当前的方法变得相当笨拙。
我明显知道Kernel#system('a | b')
,但我需要以通用方式将Ruby过滤器与外部程序过滤器混合。
答案 0 :(得分:10)
老问题,但由于它是谷歌的第一个结果之一,所以答案是:http://devver.wordpress.com/2009/10/12/ruby-subprocesses-part_3/(方法8)
简而言之:
sh = Shell.new
sh.system("a") | sh.system("b") | sh.system("c")
你可以做更复杂的事情,比如
sh.echo(my_string) | sh.system("wc") > "file_path"
xml = (sh.echo(html) | sh.system("tidy", "-q")).to_s
答案 1 :(得分:3)
如果a
,b
和c
是通常从命令行访问的命令,那么您可以使用:
captured_output = `a | b | c`
Ruby将在子shell中运行命令,并捕获STDOUT。
如果由于某种原因需要将输出路由到文件,那么您也可以将重定向添加到命令中。在这种情况下,STDOUT不会退还给您,但您可以打开文件并手动处理它:
`a | b | c > captured_output`
File.foreach('captured_output') do |li|
print li
end
它不提供与使用system
或popen3
一样多的控制权,但它很方便:
>> sin, sout, serr = Open3.popen3('ls -al | tail -1') #=> [#<IO:fd 4>, #<IO:fd 5>, #<IO:fd 7>, #<Thread:0x00000100bb8798 run>]
>> sout.read #=> "drwxr-xr-x 3 greg staff 102 Nov 2 21:01 python\n"
答案 2 :(得分:1)
使用普通红宝石,spawn
具有可用于通过管道连接进程的重定向选项。
1)创建一个管道
r,w = IO.pipe
2)用它来连接两个衍生进程
spawn(*%w[echo hello world], out: w)
spawn(*%w[tr a-z A-Z], in: r)
# => HELLO WORLD
当然,您可以在提到的Shell库中将其封装在sh.system
之类的内容中,并创建一个|()方法来进行互连。
标准库的open3模块有一些非常好用的工具,包括创建完整的管道。
答案 3 :(得分:0)
我发现的最简单的例子是redirect implementation in dash (Debian Almquist Shell)。通常,如果你想在Ruby中做同样的事情,你需要使用Ruby的IO#dup
,IO#fileno
,IO#pipe
来复制这些 fd 操作技巧。对于Ruby解释器,在C .so库中重用shell(例如dash)代码可能比使用Ruby原语组合相同的东西更容易。
我不知道任何现有的通用Ruby API用于复杂的进程间管道/重定向。如果您可以建议您想要使用的API,可能我可以参与实施。
答案 4 :(得分:0)
我知道这是一个非常老的问题,但我只是经历了这一痛苦。
基本上,我想到了一对实用程序方法,它们在fork中使用popen运行命令,将结果通过管道传递,以实现以下目的:
echo 'ABC12345 234234 24523' | wc | grep '1'
要在Ruby中执行此操作:
# Setup two pipes (the two we see in the shell command line above)
# plus one more to receive the result from.
pipe_pair1 = IO.pipe
pipe_pair2 = IO.pipe
pipe_pair_result = IO.pipe
pipe_in_out nil, pipe_pair1, ['echo', 'ABC12345 234234 24523']
pipe_in_out pipe_pair1, pipe_pair2, ['wc']
pipe_in_out pipe_pair2, pipe_pair_result, ['grep', '1']
# Get the result from the final pipe
puts "Output: #{pipe_result(pipe_pair_result)}"
方法的代码位于以下要点:https://gist.github.com/philayres/c0d96cd263329e41fa84c2e3c7b9ae7b