We've organized files in subdirectories according to tags and according to creation date. What if you would like to flatten a tree, moving all files from the sub-directories into a single directory?
"Move all the files from the tree starting at source_dir" "into dest_dir out of the tree" def flatten(source_dir, dest_dir) Dir.foreach(source_dir) do |filename| # exclude current dir and parent dir if (!filename.eql?(".") and !filename.eql?("..")) if File.directory?(filename) # subdirectory flatten(filename, dest_dir) # recursively flatten subdir else #file dirname = File.dirname(filename) filenameonly = filename[(dirname.length-1)..-1] old_name = source_dir + "/" + filename new_name = dest_dir + "/" + filenameonly puts("moving '#{old_name}' to '#{new_name}'") File.rename(old_name, new_name) end end end end # read line parameters source_dir = ARGV.shift # default source dir is current dir if (source_dir == nil) source_dir = "." end dest_dir = ARGV.shift # default destination dir current dir if (dest_dir == nil) dest_dir = "." end flatten(source_dir, dest_dir)
2 commenti:
what if you have files with same names in different subfolders
Here's my take on it. You can set max depth of folders and max attempts of renaming a file. It could be optimized still a little with support for more CL arguments, but...meh.
"Move all the files from the tree starting at source_dir"
"into dest_dir out of the tree"
# directory listings to skip
$excludes = ['.', '..', '.DS_Store']
# max file rename attempts
$max_attempts = 20
# initial directory tree depth
$depth = 0
# max allowed directory tree depth
$max_depth = 10
def flatten(source_dir, dest_dir)
# increment the tree depth
$depth += 1
# if surpassed max allowed tree depth, exit the directory
if $depth > $max_depth
puts "\n\n-- Max folder depth reached in '#{source_dir}' --\n\n"
$depth -= 1 # exit this directory
return
end
# ensure dir paths end with '/'
source_dir += "/" if source_dir[-1] != "/"
dest_dir += "/" if dest_dir[-1] != "/"
# read the items of the directory
puts "Flattening contents of '#{source_dir}' to '#{dest_dir}'\n"
Dir.entries(source_dir).each do |item|
next if $excludes.include?(item) # skip excludes
item = source_dir + item # realize full path
if File.directory?(item) # subdirectory
flatten(item, dest_dir) # recursively flatten subdir
else #file
rename_file(item, dest_dir, 0) # attempt to rename the file
end
end
# check if the directory is empty, if so delete it
# special case, ruby won't consider a dir empty if it contains .DS_Store
# delete .DS_Store first if dir otherwise empty
# also don't delete the directory if it's the root directory
begin
if (Dir.entries(source_dir) - $excludes).empty? and $depth > 1
puts "deleting #{source_dir}"
if File.file?("#{source_dir}.DS_Store")
_ = `rm "#{source_dir}.DS_Store"`
end
Dir.delete(source_dir)
end
rescue # do nothing
end
$depth -= 1 # exit this directory
end
# renames the file, moving it to the dest_dir if the file
# isn't already in the directory at dest_dir
def rename_file(filename, dest_dir, version)
# file already in dest_dir?
if File.dirname(filename) + "/" == dest_dir
puts "file #{filename} already in #{dest_dir}"
return
end
# get the straight filename, no path
fname = File.basename(filename)
# set what the new full path ought to be
new_path = dest_dir + fname
# if we are attempting new versions append the version to the basename before the extension
if version > 0
new_path = dest_dir + File.basename(filename, ".*") + "_" + version.to_s + File.extname(filename)
end
# if the new path already exists, try again
if File.file?( new_path )
puts("File '#{new_path}' exists..")
if (version > $max_attempts)
puts "Max rename attempts reached for '#{filename}'"
end
rename_file(filename, dest_dir, version += 1)
else
puts("moving '#{filename}' to '#{new_path}'")
File.rename(filename, new_path)
end
end
# START
# source dir is first argument, otherwise current directory
source_dir = ARGV.shift
# default source dir is current dir
if (source_dir == nil)
source_dir = "."
end
#destination is second argument, otherwise same as source
dest_dir = ARGV.shift
# default destination dir = source dir
if (dest_dir == nil)
dest_dir = source_dir
end
# begin the flattening process
flatten(source_dir, dest_dir)
Posta un commento