From: Brad Phelan Date: 2007-09-07T15:35:05+09:00 Subject: Chaining external commands using pipes. I have come up with a little script that works well in IRB for issuing shell commands and piping them together. For example require './shell.rb' io = Sh.ls("/bin").grep("grep") puts io generates bzegrep bzfgrep bzgrep egrep fgrep grep zegrep zfgrep zgrep I am curious as to whether the way I have implemented it is the best way. It seems kind of clunky to me. I have to spawn a new Ruby process using fork and then reopen $stdin on the child process and connect it to the output stream of the previous command. I was hoping to find a way to get around forking ruby processes to do this. Any ideas The source code is below or syntax highlighted here http://xtargets.com/snippets/posts/show/77 Brad -------------------------------- module Sh class Command def initialize(cmd, *args) @cmd = cmd @args = args @io = nil end def inspect to_s end def to_str to_s end def to_s call str = @io.read @io.close str end def | other call other.call(@io) end def method_missing(name, *args) self | Command.new(name, *args) end def call (io=nil) # The @io object can only be assigned # once return self if @io command = @cmd.to_s + " " + @args.join(" ") if io # We need a new process # and a pipe to connect the # this command to the previous # command in the chain. rd, wr = IO.pipe if fork # Parent wr.close else # Child rd.close begin # Reconnect the STDIN of the # new process to the io parameter $stdin.reopen(io) IO.popen command do |f| while txt = f.read(4096) wr.write txt end end rescue Errno::EPIPE # Ignore the broken pipe # cause the other process # has thrown away the pipe # earlier than we used outs ensure wr.close end exit end @io = rd else # This command is executed standalone. @io = IO.popen command end self end end def self.method_missing (name, *args) Command.new(name, *args) end end