[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Chaining external commands using pipes.

Brad Phelan

9/7/2007 6:34:00 AM

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/pos...

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
2 Answers

Konrad Meyer

9/7/2007 6:52:00 AM

0

On Thursday 06 September 2007 11:35:05 pm Brad Phelan wrote:
> 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/pos...
>
> 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

Stdlib shell (require 'shell') does much of that IIRC.
( http://ruby-doc.org/stdlib/libdoc/shell/rdoc/classes/... )

--
Konrad Meyer <konrad@tylerc.org> http://konrad.sobertil...

Brad Phelan

9/7/2007 7:10:00 PM

0


>
> Stdlib shell (require 'shell') does much of that IIRC.
> ( http://ruby-doc.org/stdlib/libdoc/shell/rdoc/classes/... )
>

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