# Chaining external commands using pipes

**URL:** <https://www.ruby-forum.com/t/chaining-external-commands-using-pipes/114039>\
**Category:** Ruby\
**Created:** [September 7, 2007, 8:44am UTC](https://www.ruby-forum.com/t/chaining-external-commands-using-pipes/114039 "2007-09-07T08:44:04Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![bpauly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/ecd19e/32.png) [@bpauly](https://www.ruby-forum.com/u/bpauly)\
**Post date:** [September 7, 2007, 8:44am UTC](https://www.ruby-forum.com/t/chaining-external-commands-using-pipes/114039/1 "2007-09-07T08:44:04Z")

</div>

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](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

---

<div class="post-metadata">

**Author:** ![bpauly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/ecd19e/32.png) [@bpauly](https://www.ruby-forum.com/u/bpauly)\
**Post date:** [September 7, 2007, 8:53am UTC](https://www.ruby-forum.com/t/chaining-external-commands-using-pipes/114039/2 "2007-09-07T08:53:06Z")

</div>

On Thursday 06 September 2007 11:35:05 pm Brad P. wrote:

> I am curious as to whether the way I have implemented it is the best
> 
> ```
> str = @io.read
> self | Command.new(name, *args)
> if io
> # Child
> rescue Errno::EPIPE
> else
> 
> ```
> 
> end  
> Stdlib shell (require ‘shell’) does much of that IIRC.  
> ( [http://ruby-doc.org/stdlib/libdoc/shell/rdoc/classes/Shell.html](http://ruby-doc.org/stdlib/libdoc/shell/rdoc/classes/Shell.html) )

---

<div class="post-metadata">

**Author:** ![bpauly](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/ecd19e/32.png) [@bpauly](https://www.ruby-forum.com/u/bpauly)\
**Post date:** [September 7, 2007, 9:16pm UTC](https://www.ruby-forum.com/t/chaining-external-commands-using-pipes/114039/3 "2007-09-07T21:16:37Z")

</div>

> Stdlib shell (require ‘shell’) does much of that IIRC.  
> ( [http://ruby-doc.org/stdlib/libdoc/shell/rdoc/classes/Shell.html](http://ruby-doc.org/stdlib/libdoc/shell/rdoc/classes/Shell.html) )

Perhaps but there is zero documentation for any of the classes in the  
shell library and I don’t see anything specific to creating pipes  
between processes there.

Brad
