You want to rename a bunch of files programmatically: for instance, to normalize the filename case or to change the extensions.
Use the Find module in the Ruby standard library. Heres a method that renames files according to the results of a code block. It returns a list of files it couldn rename, because their proposed new name already existed:
require find
module Find
def rename(*paths)
unrenamable = []
find(*paths) do |file|
next unless File.file? file # Skip directories, etc.
path, name = File.split(file)
new_name = yield name
if new_name and new_name != name
new_path = File.join(path, new_name)
if File.exists? new_path
unrenamable << file
else
puts "
Renaming #{file} to #{new_path}" if $DEBUG
File.rename(file, new_path)
end
end
end
return unrenamable
end
module_function(:rename)
end
This addition to the Find module makes it easy to do things like convert all filenames to lowercase. Ill create some dummy files to demonstrate:
require fileutils tmp_dir = mp_files Dir.mkdir(tmp_dir) [CamelCase.rb, OLDFILE.TXT, OldFile.txt].each do |f| FileUtils.touch(File.join(tmp_dir, f)) end tmp_dir = File.join(tmp_dir, subdir) Dir.mkdir(tmp_dir) [i_am_SHOUTING, I_AM_SHOUTING].each do |f| FileUtils.touch(File.join(tmp_dir, f)) end
Now lets convert these filenames to lowercase:
$DEBUG = true
Find.rename(./) { |file| file.downcase }
#
Renaming ./tmp_files/subdir/I_AM_SHOUTING to ./tmp_files/subdir/i_am_shouting
# Renaming ./tmp_files/OldFile.txt to ./tmp_files/oldfile.txt
# Renaming ./tmp_files/CamelCase.rb to ./tmp_files/camelcase.rb
# => ["./OldFile.txt", "./dir/i_am_SHOUTING"]
Two of the files couldn be renamed, because oldfile.txt and subdir/i_am_shouting were already taken.
Lets add a ".txt" extension to all files that have no extension:
Find.rename(./) { |file| file + .txt unless file.index(.) }
#
Renaming ./tmp_files/subdir/i_am_shouting to ./tmp_files/subdir/i_am_shouting.txt
#
Renaming ./tmp_files/subdir/i_am_SHOUTING to ./tmp_files/subdir/i_am_SHOUTING.txt #
# => []
Renaming files in bulk is a very common operation, but theres no standard command-line application to do it because renaming operations are best described algorithmically.
The Find.rename method makes several simplifying assumptions. It assumes that you want to rename regular files and not directories. It assumes that you can decide on a new name for a file based solely on its filename, not on its full path. It assumes that youll handle in some other way the files it couldn rename.
Another implementation might make different assumptions: it might yield both path and name, and use autoversioning to guarantee that it can rename every file, although not necessary to the exact filename returned by the code block. It all depends on your needs.
Perhaps the most common renaming operation is modifying the extensions of files. Heres a method that uses Find.rename to make this kind of operation easier:
module Find
def change_extensions(extension_mappings, *paths)
rename(*paths) do |file|
base, extension = file.split(/(.*)./)[1..2]
new_extension = extension
extension_mappings.each do |re, ext|
if re.match(extension)
new_extension = ext
break
end
end
"#{base}.#{new_extension}"
end
end
module_function(:change_extensions)
end
This code uses Find.change_extensions to normalize a collection of images. All JPEG files will be given the extension ".jpg", all PNG files the extension ".png", and all GIF files the extension ".gif".
Again, well create some dummy image files to test:
tmp_dir = mp_graphics Dir.mkdir(tmp_dir) [my.house.jpeg, Construction.Gif, DSC1001.JPG, 52.PNG].each do |f| FileUtils.touch(File.join(tmp_dir, f)) end
Now, lets rename:
Find.change_extensions({/jpe?g/i => jpg,
/png/i => png,
/gif/i => gif}, tmp_dir)
#
Renaming tmp_graphics/52.PNG to tmp_graphics/52.png
#
Renaming tmp_graphics/DSC1001.JPG to tmp_graphics/DSC1001.jpg
# Renaming tmp_graphics/Construction.Gif to tmp_graphics/Construction.gif
# Renaming tmp_graphics/my.house.jpeg to tmp_graphics/my.house.jpg
Strings
Numbers
Date and Time
Arrays
Hashes
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Internet Services
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
User Interface
Extending Ruby with Other Languages
System Administration