From: mathew
Date: 2005-07-29T07:46:01+09:00
Subject: Re: Sed -> Ruby : .. and ...
Keith Fahlgren wrote:
> ruby:
> #!/usr/bin/env ruby
>
> files = ARGV
>
> files.each do |arg|
> f = File.open(arg)
> puts "\nOpening file #{f}"
> working_file = f.read
>
> working_file.gsub!(/MATCH/,'GLOBAL REPLACEMENT')
>
> puts "\nDoing ACTION in #{arg}"
> f = File.new(arg, "w")
> puts "\nWriting #{f} now"
> f.print(working_file)
> f.close
> end
One problem with this code is that if you break out of it, you might
find that it deleted your data.
A better approach is to rename the data file to a temporary file, write
the data, then unlink the temporary file.
The best approach is to write the new data to temporary file #1, rename
the input file to a different temporary file #2 and then immediately
rename #1 to the input filename, and finally delete temporary file #2.
That minimizes the window in which the state on disk is not what you
want it to be. It ensures that the worst possible case is that you have
a temporary file left behind in the data directory, and the input file
contains either the data from before processing, or the data after
processing.
Unfortunately, implementing the best approach is non-trivial, because
you have to worry about rename not working across filesystem
boundaries... But you should at least make sure you don't delete the
user's data. :-)
> Here's the one I have problems with (we had a working Perl equivalent
> but are trying to abandon Perl).
>
> sed:
> /BEGIN RANGE/,/END RANGE/{
> s/MATCH/REPLACEMENT/g
> }
working_file.gsub!(/(?=BEGIN RANGE)(.*?)(?=END RANGE)/m) {||
$1.gsub(/MATCH/m, 'REPLACEMENT')
}
(?= ) is a zero-width assertion; the regexp engine matches the BEGIN
RANGE and END RANGE, but then forgets about them when it comes to
removing and replacing, so they're still left there in the final string.
(.*?) is a non-greedy match, which ensures that we get the shortest
possible match between a BEGIN RANGE and an END RANGE; otherwise, if you had
BEGIN RANGE
MATCH
END RANGE
MATCH
BEGIN RANGE
MATCH
END RANGE
all three MATCHes would be replaced.
The block just does a normal global search and replace on the character
sequence.
Don't forget to comment what those three lines do, for the benefit of
the person who has to maintain the code...
mathew
--
WE HAVE TACOS