From: Konrad Meyer Date: 2007-09-07T15:52:24+09:00 Subject: Re: Chaining external commands using pipes. --nextPart2082345.jyFlp0tXVb Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline 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=20 > shell commands and piping them together. For example >=20 > require './shell.rb' >=20 > io =3D Sh.ls("/bin").grep("grep") > puts io >=20 > generates >=20 > =09 > bzegrep > bzfgrep > bzgrep > egrep > fgrep > grep > zegrep > zfgrep > zgrep >=20 > I am curious as to whether the way I have implemented it is the best=20 > way. It seems kind of clunky to me. I have to spawn a new Ruby process=20 > 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 >=20 > The source code is below or syntax highlighted here > http://xtargets.com/snippets/posts/show/77 >=20 > Brad >=20 > -------------------------------- >=20 > module Sh > class Command >=20 > def initialize(cmd, *args) > @cmd =3D cmd > @args =3D args > @io =3D nil > end >=20 > def inspect > to_s > end >=20 > def to_str > to_s > end >=20 > def to_s > call > str =3D @io.read > @io.close > str > end >=20 > def | other > call > other.call(@io) > end >=20 > def method_missing(name, *args) > self | Command.new(name, *args) > end >=20 > def call (io=3Dnil) >=20 > # The @io object can only be assigned > # once > return self if @io >=20 > command =3D @cmd.to_s + " " + @args.join(" ") >=20 > if io > # We need a new process > # and a pipe to connect the > # this command to the previous > # command in the chain. > rd, wr =3D IO.pipe >=20 > 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 =3D 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 =3D rd > else > # This command is executed standalone. > @io =3D IO.popen command > end > self > end > end >=20 > 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/Shell.html ) =2D-=20 Konrad Meyer http://konrad.sobertillnoon.com/ --nextPart2082345.jyFlp0tXVb Content-Type: application/pgp-signature; name=signature.asc Content-Description: This is a digitally signed message part. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQBG4PUkCHB0oCiR2cwRAqxLAJ4vPkcPTy+CC1aEh68MQszgOh3d2QCdEh6x 6QJV6Otl20G4EHZlFUCQOhU= =wE3f -----END PGP SIGNATURE----- --nextPart2082345.jyFlp0tXVb--