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