On 12 May 2011 18:05, Michal S. [email protected] wrote:
cmdA directly, on its stdin, and similarily for cmdC and cmdB.
Here I am not interested in feeding cmdA some particular input (eg. it
can read /dev/null for all I care) but in general gluing arbitrary fd
to its stdin might be desirable in other cases.
Thanks
Michal
OK, thanks for all the replies.
It seems this is not doable with ruby 1.8 but spawn and similar
methods in 1.9 grew the named arguments which include the file
descriptors.
Here is a working (although not polished) solution for ruby 1.9.
First a short testing script called cmd:
#!/usr/bin/ruby
prefix = ARGV[0] + “:”
append = ARGV[1]
while l = STDIN.gets do
STDOUT << l
STDERR << prefix << l
end
STDOUT.puts append
And the long script with pipes that calls the above:
#!/usr/bin/ruby1.9.1
Debian calls ruby 1.9 ruby1.9.1
pipes = []
(1…4).each {pipes << IO.pipe}
errs = []
(1…3).each {errs << IO.pipe}
writer = pipes[0][1]
reader = pipes[3][0]
i = 1
Careful about pipe direction, it only works one way.
pids = [
spawn(“cmd”, “a”, “aa”, :in => pipes[0][0], :out => pipes[1][1], :err
=> errs[0][1] ),
spawn(“cmd”, “b”, “bb”, :in => pipes[1][0], :out => pipes[2][1], :err
=> errs[1][1] ),
spawn(“cmd”, “c”, “cc”, :in => pipes[2][0], :out => pipes[3][1], :err
=> errs[2][1] ),
]
We don’t really want to see these pipes, perhaps some
Open3.pipeline_* method would create them out of sight
pipes.flatten.select{|p| p != writer && p != reader}.each{|p|p.close}\
maxlen = 128 # some arbitrary size for chunk of data read at once
outputs = errs.collect{|r,w|r}
outputs << reader
wsel = [writer]
while true do
ios = IO.select(outputs, wsel, nil, 1)
STDERR << ‘.’
string = "%4i\n" % i
if writer then
begin
result = writer.write_nonblock(string)
i = i + 1
if ( i > 1000 ) then
writer.close
writer = nil
wsel = nil
end
rescue IO::WaitWritable, Errno::EINTR
end
end
outputs.each{|io|
begin
result = io.read_nonblock(maxlen)
STDOUT << result
rescue IO::WaitReadable, Errno::EINTR, EOFError
if $!.is_a? EOFError then
STDERR.puts “EOF”
outputs.reject!{|o| o == io }
end
end
}
(0…3).each{|i| p = pids[i]
if p and Process.waitpid(p, Process::WNOHANG) then
STDOUT.puts $?.inspect
pids[i] = nil
end
}
break if !ios && pids.select{|pid| pid} == []
end