#!/usr/bin/env ruby # Start Date: Sunday December 2, 2007 (v0.9) # Most Recent Update: Saturday January 26, 2008 # Current Version: 1.2 # Author: Joseph Pecoraro # Contact: joepeck02@gmail.com # Decription: Default behavior is a multi-line search and replace utility that # uses a regular expression for searching and allows back references to # captured groups from the pattern to appear in the replacement text # Global States line_processing = false case_sensitive = false global_replace = true modify_original = false # Usage Message to print $program_name = $0.split(/\//).last usage = <= 2 find_str = ARGV[0] replace = ARGV[1].dup first_filename = 2 ARGV << nil if ARGV.size == 2 # User is allowed to wrap the find regex in /'s (this removes them) find_str = find_str[1..(find_str.length-2)] if find_str =~ /^\/.*?\/$/ # Bad Arguments, show usage else puts usage exit 1 end # Make find_str into a Regexp object if case_sensitive find = Regexp.new( find_str ) else find = Regexp.new( find_str, Regexp::IGNORECASE ) end # Map metacharacters in the replace portion replace.gsub!(/\\[\\ntrvfbae]/) do |match| case match when "\\\\" then match = "\\" # A backslash when "\\n" then match = "\n" # Newline when "\\t" then match = "\t" # Tab when "\\r" then match = "\r" # Carriage Return when "\\v" then match = "\v" # Vertical Tab when "\\f" then match = "\f" # Formfeed when "\\b" then match = "\b" # Backspace when "\\a" then match = "\a" # Bell when "\\e" then match = "\e" # Escape end end # Loop through all the filenames doing the find/replace first_filename.upto(ARGV.size-1) do |i| # Check for Possible File Errors or if the filename is nil make it STDIN filename = ARGV[i] unless filename.nil? if !File.exist? filename err("#{filename}: No such file") elsif File.directory? filename err("#{filename}: This is a directory, not a file.") elsif !File.readable? filename err("#{filename}: File is not readable by this user.") elsif !File.writable? filename err("#{filename}: File is not writable by this user.") end else filename = STDIN.fileno end # Setup the stream to print to if modify_original && filename != STDIN.fileno then temp_filename = filename + '.tmp' stream = File.new(temp_filename, File::CREAT|File::TRUNC|File::RDWR, 0644) else stream = STDOUT end # Default Behavior (and basicically what they all do) # 1. Open the file # 2. Read text as 1 big sting (memory intensive) or Line by Line # 3. Run the Find/Replace globally or non-globally # 4. Print the result to a stream if line_processing and global_replace then File.new(filename).readlines.each { |line| stream.puts line.gsub(find,replace) } elsif line_processing and !global_replace then File.new(filename).readlines.each { |line| stream.puts line.sub(find,replace) } elsif !line_processing and global_replace stream.puts File.new(filename).read.gsub(find,replace) else stream.puts File.new(filename).read.sub(find,replace) end # If the stream was a temp file then clean up if modify_original && filename != STDIN.fileno then stream.close File.rename(temp_filename, filename) end end # Successful exit 0