bulk_file_rename
#!/usr/bin/env ruby
# A Ruby bulk file renaming script
require 'fileutils'
require 'pry'
require 'colored'
require 'trollop'
class BulkFileRename
include FileUtils
attr_accessor :file_count, :renamed_count, :would_count, :options, :elapsed
def self.run(*args)
start_time = Time.now
opts = Trollop::options do
opt(:directories, 'A colon-separated list of directories to search', type: :string, short: 'd', required: true)
opt(:file_pattern, 'A globular expression filename search pattern', type: :string, short: 'f', required: true)
opt(:replace_pattern, "A SED-type replace pattern: 's/search/replace/'", type: :string, short: 'p', required: true)
opt(:alt_output, 'Alternative output', short: 'a')
opt(:recursive, 'Recursively search directories', short: 'r')
opt(:color, 'Print colored output', default: true, short: 'c')
opt(:test_run, 'Test (Dry) run: Only report what would be renamed', short: 't')
end
unless opts[:replace_pattern] && opts[:replace_pattern].match(/s\/[^\/]+\/[^\/]*\//)
Trollop::die("Use a SED-like expression for --replace-pattern='s/search/replace/'")
end
unless ARGV.empty?
opts[:directories] = ARGV.first.split(':')
end
opts[:directories] = [opts[:directories]] unless opts[:directories].respond_to?(:each)
instance = BulkFileRename.new(opts)
instance.process
instance.elapsed = Time.now - start_time
instance.report_summary
end
def initialize(opts)
self.file_count = 0
self.renamed_count = 0
self.would_count = 0
self.options = opts
end
def color(string, clr)
if self.options[:color]
string.send(clr)
else
string
end
end
def report_summary
puts
puts(color(">>> Processed #{file_count.to_i} files in [#{elapsed}] seconds", :red))
puts(color(">>> Renamed #{renamed_count.to_i} files", :red))
if self.options[:test_run]
puts(color(">>> Would have renamed #{would_count.to_i} files", :red))
end
end
def report_move(source, destination)
if self.options[:alt_output]
puts(%Q{"#{color(source, :green)}","#{color(destination, :yellow)}"})
else
verb = self.options[:test_run] ? 'Would rename' : 'Renaming'
puts(%Q{#{verb} "#{color(source, :green)}" to "#{color(destination, :yellow)}"})
end
end
def rename_file(current, regex, replace, global)
if !!global
current.gsub(regex, replace)
else
current.sub(regex, replace)
end
end
def process(directories = self.options[:directories])
x, search, replace, global = self.options[:replace_pattern].split(/\//)
directories.each do |directory|
cd(directory)
Dir.glob(self.options[:file_pattern]).each do |current_title|
if self.options[:recursive] && File.directory?(current_title)
process([current_title])
break
end
self.file_count += 1
searchx = Regexp.new(search)
new_name = rename_file(current_title, searchx, replace, global)
self.would_count += 1 unless new_name == current_title
report_move(current_title, new_name)
unless self.options[:test_run]
binding.pry
mv(current_title, new_name)
self.renamed_count += 1
end
end
end
end
end
BulkFileRename.run(ARGV)