Erik =?ISO-8859-1?Q?B=E5gfors?= <erik / bagfors.nu> wrote:
> On 17 Jul 2001 19:55:19 +0900, Steve Hill wrote:
> > Hi,
> > I'm sure this isn't really a ruby specific question, but since I scipt
> > in ruby, maybe someone has a good answer...
> > 
> > Some of the scripting relies on some of the standard unix tools to do
> > its work, called using backquotes. e.g. the following facet which
> > processes the columns of a file previously created with grep.
> > 
> > `grep FOO foo.txt > foo.tmp`
> > 
> > flag?=false
> > hash=Hash.new
> > IO.for_each("foo.tmp") do |line|
> >    unless flag? do
> >       cols=line.split
> >       (0...cols).each {|i| hash[i]=Bar.new}
> >    end
> > 
> >    cols=line.split
> >    hash.each {|k,v| v.process(cols[i]) }  #A
> > end
> > 
> > The problem is that the script may fail at the line marked A because
> > the file "foo.tmp" has either not been written at all, or has not been
> > completely written.
> > 
> > The first problem can be solved by inserting the following section
> > after the grep.
> > 
> > while !File.stat?("foo.tmp").size? 
> >    sleep 0.001
> > end
> > 
> > Does anyone know how to test that "foo.tmp" has been completely
> > written?
> > 
> 
> Don't write to a file.  Write to the program instead.  Something like
> this I think:
> 
> IO.popen("grep FOO foo.txt").each do |line|
>     # do stuff with |line|
> end

Better yet, do all of the processing in pure Ruby and get much lower 
overhead.  A fork and exec and a bunch of reads and writes and more reads is 
a lot more than just doing the same in Ruby.  I like to use more verbose 
syntax than many:

lines = []
File.open("foo.txt", "r") {|file|
    file.each_line {|line|
        if line =~ /FOO/
	    lines.push(line)
	end
    }
}

Alternatively, to have it read the whole file into memory before processing 
it:

lines = File.open("foo.txt", "r") {|file| file.readlines.grep(/FOO/)}

or some shorter alternative thereof using newer mechanisms like 
File.readline.  You could even create a method to make things even easier:

class << File
    unless defined?(grep)
        def grep(filename, regex, can_fail = true)
            lines = []
            begin
                File.open(filename, "r") {|file|
                    file.each_line {|line|
                        lines.push(line) if line =~ regex
                    }
                }
            rescue SystemCallError => e
                raise(e) if can_fail
            end
            lines
        end
    end
end

Then you'd be able to do:

lines = File.grep("foo.txt", /FOO/, false) # here, returns [] on failure
                                           # instead of raising an exception

-- 
 Brian Fundakowski Feldman           \  FreeBSD: The Power to Serve!  /
 green / FreeBSD.org                    `------------------------------'