# Copying files and changing their names

**URL:** <https://www.ruby-forum.com/t/copying-files-and-changing-their-names/88807>\
**Category:** Ruby\
**Created:** [March 14, 2007, 4:25pm UTC](https://www.ruby-forum.com/t/copying-files-and-changing-their-names/88807 "2007-03-14T16:25:51Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![samf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/22d042/32.png) [@samf](https://www.ruby-forum.com/u/samf)\
**Post date:** [March 14, 2007, 4:25pm UTC](https://www.ruby-forum.com/t/copying-files-and-changing-their-names/88807/1 "2007-03-14T16:25:51Z")

</div>

Hi all,

I have a directory with numerous folders, each of which contains  
numerous folders and/or files.

Each of the files in each of these folders has a number. I want to  
iterate through all these files, and, for every file that ends in a  
‘[filename]-9’, I want to COPY the file and rename it  
‘[filename]-final’.

Is there a simple way to do this in Ruby?

Any help much appreciated!  
Sam

---

<div class="post-metadata">

**Author:** ![samf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/22d042/32.png) [@samf](https://www.ruby-forum.com/u/samf)\
**Post date:** [March 14, 2007, 4:39pm UTC](https://www.ruby-forum.com/t/copying-files-and-changing-their-names/88807/2 "2007-03-14T16:39:15Z")

</div>

Alle mercoledÃ¬ 14 marzo 2007, SamF ha scritto:

> Is there a simple way to do this in Ruby?
> 
> Any help much appreciated!  
> Sam

NOT TESTED - make a trial with some useless directory before using it on  
real  
data

require ‘find’  
require ‘fileutils’

Find.find(’.’) do |f|  
FileUtils.cp(f,f.sub(/-9$/, ‘-final’)) if File.file?(f) and f.match  
/-9$/)  
end

Find.find calls the block passing the name of each file or directory it  
contains, recursively. In the block, we use the FileUtils.cp method to  
copy f  
to the file whose name is obtained by rmoving the final -9 and adding  
-final,  
but only if the name is the name of a file (not of a directory) and if  
the  
name ends with -9.

I hope this helps

Stefano

---

<div class="post-metadata">

**Author:** ![samf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/22d042/32.png) [@samf](https://www.ruby-forum.com/u/samf)\
**Post date:** [March 14, 2007, 5:09pm UTC](https://www.ruby-forum.com/t/copying-files-and-changing-their-names/88807/3 "2007-03-14T17:09:52Z")

</div>

Stefano C. wrote:

> NOT TESTED - make a trial with some useless directory before using it on  
> real  
> data

Hi Stefano (anzi, ‘ciao!’),

Thank you very much – that has helped me tremendously. I have one  
further question though. What if, instead of the number “9”, I wanted to  
copy the file with the HIGHEST number.

For example, my files might be

example1.txt  
example2.txt  
test1.txt  
test2.txt  
test3.txt

If I wanted to change example2.txt to example-final.txt, and test3.txt  
to test-final.txt, how could I iterate throught the files to find the  
file with the highest number?

Grazie mille per qualsiasi aiuto,  
Sam

---

<div class="post-metadata">

**Author:** ![samf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/22d042/32.png) [@samf](https://www.ruby-forum.com/u/samf)\
**Post date:** [March 14, 2007, 6:26pm UTC](https://www.ruby-forum.com/t/copying-files-and-changing-their-names/88807/4 "2007-03-14T18:26:58Z")

</div>

Sam Fent wrote:

> If I wanted to change example2.txt to example-final.txt, and test3.txt  
> to test-final.txt, how could I iterate throught the files to find the  
> file with the highest number?

Ok, so I worked it out myself, as I probably should have from the  
beginning.

This is almost certainly not the most efficient code, in that it  
iterates over the same directories several times, but here it is, in  
case any future person wants to do the same thing (or any present person  
wants to make it more efficient).

require ‘find’  
require ‘fileutils’

usedNames = []

Find.find(’.’) do |f|  
if (File.file?(f) and f.match(/txt$/))  
name = f[/.\*V/][0…-2]  
if (!usedNames.include?(name))  
usedNames += [name]  
versions = []

```
  # find the latest version number
  Find.find('.') do |f|
    if (File.file?(f) and f.match(/#{name}.*txt$/))
      versionNumber = f[name.length+1..-5]
      versions += [versionNumber]
    end
  end
  versions = versions.sort
  lastVersionNumber = versions[versions.length-1]

  # copy file and re-name it FINAL
  if (!lastVersionNumber.match(/.*FINAL.*/))
    Find.find(name+"V"+lastVersionNumber+".txt") do |g|
      puts "Changing file " + g + " to: " + 

```

g.sub(/#{lastVersionNumber}/,"\_FINAL")  
FileUtils.cp(g,g.sub(/#{lastVersionNumber}/,“FINAL”))

```
    end
  end
end

```

end  
end

---

<div class="post-metadata">

**Author:** ![samf](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/22d042/32.png) [@samf](https://www.ruby-forum.com/u/samf)\
**Post date:** [March 14, 2007, 6:43pm UTC](https://www.ruby-forum.com/t/copying-files-and-changing-their-names/88807/5 "2007-03-14T18:43:45Z")

</div>

Alle mercoledÃ¬ 14 marzo 2007, Sam Fent ha scritto:

> file with the highest number?
> 
> Grazie mille per qualsiasi aiuto,  
> Sam

This should work:

require ‘find’  
require ‘set’  
require ‘file\_utils’

Find.find(’.’) do |f|

# consider only directories, we’ll take care of files later

if File.directory?(f)  
# create a Set containing the names of the files in the directory f  
[1]  
entries=Set.new(Dir.entries(f).reject{|e| File.directory?(e)})  
#separate the files basing on their basename (the part before  
-number) [2]  
names=entries.classify{|e| e.match(/^.\*-\d+$/)[1]}  
# for each of the basenames  
names.each\_value do |v|  
# sort the set basing on the number and select the last  
name=v.sort\_by{|n| n.match(/-(\d+)/)[1].to\_i}.last  
# copy it to the new name. name is relative to f, so we prepend it  
FileUtils.cp “#{f}#{name}”, “#{f}#{name.sub(/-\d+$/, ‘-final’)}”  
end  
end  
end

The line marked by [2] creates a hash of sets, each of them containing  
the  
files with the same basename. This method is the only reason to use a  
set in  
line [1], instead of keeping the array. For instance, if the directory f  
contains the files  
a-1  
a-2  
a-3  
b-1  
b-2  
c-1  
c-2  
c-3  
c-4

the result of line [2] will be a hash with keys ‘a’, ‘b’ and ‘c’. The  
keys ‘a’  
will contain a set with elements ‘a-1’, ‘a-2’, ‘a-3’, and so on for the  
other  
keys.

Stefano
