tags:

views:

44

answers:

2

Hi everyone,

I'm using Mac OS X and I'm trying to write a little script that moves a file to a specific folder. I'm using the FileUtils API since I don't want to run system specific commands (system("mv a b").

The script looks something like this:

#!/usr/bin/env ruby
require 'rubygems'
require 'escape'
require 'fileutils'

absolut_input_filename = Escape.shell_single_word ARGV[0]
move_folder = Escape.shell_single_word "/move/to/folder"      
FileUtils.mv absolut_input_filename, move_folder

As long as the input filename contains no space, everything works fine. But as soon as I put in a file with a space the error output is something like this:

./scripts/success /path/to/file\ with\ space

/usr/local/Cellar/ruby/1.9.2-p0/lib/ruby/1.9.1/fileutils.rb:1418:in `stat': No such file or directory - '/path/to/file with space' (Errno::ENOENT)
        from /usr/local/Cellar/ruby/1.9.2-p0/lib/ruby/1.9.1/fileutils.rb:1418:in `block in fu_each_src_dest'
        from /usr/local/Cellar/ruby/1.9.2-p0/lib/ruby/1.9.1/fileutils.rb:1432:in `fu_each_src_dest0'
        from /usr/local/Cellar/ruby/1.9.2-p0/lib/ruby/1.9.1/fileutils.rb:1416:in `fu_each_src_dest'
        from /usr/local/Cellar/ruby/1.9.2-p0/lib/ruby/1.9.1/fileutils.rb:504:in `mv'
        from ./scripts/success:8:in `<main>'

For escaping I use the 'escape' gem in version 0.0.4 in which the shell_single_word looks like this:

  def shell_single_word(str)
    if str.empty?
      "''"
    elsif %r{\A[0-9A-Za-z+,./:=@_-]+\z} =~ str
      str
    else
      result = ''
      str.scan(/('+)|[^']+/) {
        if $1
          result << %q{\'} * $1.length
        else
          result << "'#{$&}'"
        end
      }
      result
    end
  end
A: 

I don't actually know from Ruby, so take this with a grain of salt, but I know the underlying OS primitives inside and out, and from C you can do this with rename(2). Therefore, from Ruby, you should be able to do this with File.rename, which requires no quoting at all. Try this:

#! /usr/bin/env ruby

tomove = ARGV[0]
target = "/path/to/target/folder"

File.rename(tomove, File.join(target, File.basename(tomove)))
Zack
+3  A: 

you can just not use escape

require 'fileutils'
absolut_input_filename = ARGV[0]
move_folder = "/move/to/folder"
FileUtils.mv absolut_input_filename, move_folder
ghostdog74
More precisely `FileUtils` expects an unescaped string, so things start to break as soon as leifg escapes a space. If he passes it through unescaped (as in your example) it will work just fine.
Ken Bloom
that worked perfectly, thanks for the advice
leifg