Renaming Files

Hi, I'm just trying to rename a whole load of files in a directory. Been palying with IRB. My code doesn't work, no doubt because I fluffed it.

irb(main):041:0> Dir.entries('.').each do |f|
irb(main):042:1* next if f=="." or f==".."
irb(main):043:1> File.move( f, f.gsub!( /\s/, '_' ) )
irb(main):044:1> end
Errno::ENOENT: No such file or directory - Animating_Reality_2pm_26th_July_2007.MP3
         from /opt/local/lib/ruby/1.8/ftools.rb:106:in `stat'
         from /opt/local/lib/ruby/1.8/ftools.rb:106:in `move'
         from (irb):43
         from (irb):41:in `each'
         from (irb):41

What's the best way of doing this, please?

Regards

Gabriel

···

from :0

The problem here is the ! on the gsub. This is changing the contents of f *before* it gets passed to the function:

def show(a, b)
    puts "[#{a}] [#{b}]"
end

x = "Here is a string"

show(x, x.gsub!(/\s/,'_'))

results in

[Here_is_a_string] [Here_is_a_string]

But change the gsub! to a plain gsub and you get

[Here is a string] [Here_is_a_string]

because a plain gsub returns a copy of the modified string without modifying the original.

Only use the ! versions when you are absolutely sure you need to.

Alle giovedì 23 agosto 2007, Gabriel Dragffy ha scritto:

irb(main):043:1> File.move( f, f.gsub!( /\s/, '_' ) )

You need gsub, not gsub!. gsub! modifies the string it's called on (f), so
File.move the modified string also as first argument. And, since a file with
the modifed name doesn't exist, it raises an exception. Besides, gsub! will
return nil if no replacement happens (i.e, if f doesn't contain spaces). This
would also result in an exception. gsub, instead, creates a new string and
modifies it, so File.move receives two different strings.

I hope this helps

Stefano

Thank you so much for these replies (Peter & Stefano). That makes perfect sense. As soon as you pointed out gsub! was doing what is was supposed to :slight_smile:
Thanks. I just renamed a directory of about 30 files in 0.5 seconds with that one.

Just another quicky, if I wanna rename all the files in the directory is what I did OK, using:
  next if f=="." or f==".."

I just feel there must a better way?

Best regards Gabriel

···

On 23 Aug 2007, at 12:27, Peter Hickman wrote:

The problem here is the ! on the gsub. This is changing the contents of f *before* it gets passed to the function:

def show(a, b)
   puts "[#{a}] [#{b}]"
end

x = "Here is a string"

show(x, x.gsub!(/\s/,'_'))

results in

[Here_is_a_string] [Here_is_a_string]

But change the gsub! to a plain gsub and you get

[Here is a string] [Here_is_a_string]

because a plain gsub returns a copy of the modified string without modifying the original.

Only use the ! versions when you are absolutely sure you need to.

Hi,

Alle giovedì 23 agosto 2007, Gabriel Dragffy ha scritto:
> irb(main):043:1> File.move( f, f.gsub!( /\s/, '_' ) )

You need gsub, not gsub!. [...] gsub, instead, creates a new string and
modifies it, so File.move receives two different strings.

I suppose the evaluation order of arguments is left to right
and f is handed over to File#move as long as it is the old
version. Yet, before is gets used it becomes modified by its
gsub! method.

Independently from such considerations it is never a good
idea to rely on evaluation orders anywhere else than in
and/&&/or/|| expressions. If File#move were a method taking
a block it surely were no good programming style either to
modify f inside that:

  some_method( f) do ... ; f.gsub! ... ; ... end

This is admittedly not a beginners topic and probably far
from what Gabriel expected to meet.

Bertram

···

Am Donnerstag, 23. Aug 2007, 20:29:26 +0900 schrieb Stefano Crocco:

--
Bertram Scharpf
Stuttgart, Deutschland/Germany
http://www.bertram-scharpf.de

Alle giovedì 23 agosto 2007, Gabriel Dragffy ha scritto:

Just another quicky, if I wanna rename all the files in the directory
is what I did OK, using:
next if f=="." or f==".."

I just feel there must a better way?

If you want to rename only files, then you should do

  next unless File.file? f

This way, you skip not only the given directory and its parent, but also any
directory inside the current. If you're sure the given directory contains
only files, then you're approach and mine should be equivalent (although, in
my opinion, mine makes clearer why you're skipping those entries).

Stefano

Aha yes, perhaps in my situation both equal, but yours is surely cleaner and in another situation it would save me from nuking the subdirs. Thank you, Stefano.

···

On 23 Aug 2007, at 12:54, Stefano Crocco wrote:

Alle giovedì 23 agosto 2007, Gabriel Dragffy ha scritto:

Just another quicky, if I wanna rename all the files in the directory
is what I did OK, using:
        next if f=="." or f==".."

I just feel there must a better way?

If you want to rename only files, then you should do

  next unless File.file? f

This way, you skip not only the given directory and its parent, but also any
directory inside the current. If you're sure the given directory contains
only files, then you're approach and mine should be equivalent (although, in
my opinion, mine makes clearer why you're skipping those entries).

Stefano