Topa_14
Topa_14

Reputation: 199

Directory with a number of files and subdirectories: I need to move those files into each subdirectories,as per file name in Ruby

I have one directory with a number of files and subdirectories. I need to move those files into each subdirectories, depending on their naming. For instance:

Files:

Hello.doc
Hello.txt
Hello.xls
This_is_a_test.doc
This_is_a_test.txt
This_is_a_test.xls
Another_file_to_move.ppt
Another_file_to_move.indd

Subdirectories:

Folder 01 - Hello
Folder 02 - This_is_a_test
Folder 03 - Another_file_to_move

What I need is to move the three files named Hello into folder Folder 01 - Hello; the three files called This_is_a_test into directory Folder 02 - This_is_a_test and the two files named Another_file_to_move into directory called Folder 03 - Another_file_to_move. I have hundreds of files, not just these ones.

As it can be seen, the folder name contain the name of the file at the end, but at the beginning there is a Folder + \s + a number + \s + a -. This is a global pattern.

Any help?

Upvotes: 2

Views: 88

Answers (2)

Aetherus
Aetherus

Reputation: 8898

And here is a faster but not cross-platform solution (assuming your working directory is the directory containing the files and subdirectories), and the code is a little bit chaotic:

subdirectories = `ls -d ./*/`.lines.each(&:chomp!)

subdirectories.each do |dir|
  basename = dir =~ /\bFolder \d+ - (\w+)\/$/ && $1
  next unless basename
  `mv ./#{basename}.* #{dir}`
end

Upvotes: 0

Aetherus
Aetherus

Reputation: 8898

Don't rush, try to solve your problem step by step. I would solve your problem in the following steps:

1. Separate files from subdirectories

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}
# TODO ...

2. Iterate over the files and retrieve the basename of each file, without extension

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}

files.each do |file|
  basename = File.basename(file, '.*')
  # TODO ...
end

3. Find the subdirectory that the file should go to

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}

files.each do |file|
  basename = File.basename(file, '.*')
  subdirectory = subdirectories.find {|d| File.basename(d) =~ /^Folder \d+ - #{Regexp.escape(basename)}$/}
  # TODO ...
end

4. Move the file into that directory

require 'fileutils'

subdirectories, files = Dir['/path/to/the/directory/*'].partition{|path| File.directory?(path)}

files.each do |file|
  basename = File.basename(file, '.*')
  subdirectory = subdirectories.find {|d| File.basename(d) =~ /^Folder \d+ - #{Regexp.escape(basename)}$/}
  FileUtils.mv(file, subdirectory + '/')
end

Done. But finding subdirectories using regexp is expensive and we don't want to do this for each file. Can you optimize it?

HINT 1: Trade memory for time.
HINT 2: Hash.

Upvotes: 3

Related Questions