196

I am trying to create a directory with the following code:

Dir.mkdir("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test") unless File.exists?("/Users/Luigi/Desktop/Survey_Final/Archived/Survey/test") 

However, I'm receiving this error:

No such file or directory - /Users/Luigi/Desktop/Survey_Final/Archived/Survey/test (Errno::ENOENT)

Why is this directory not being created by the Dir.mkdir statement above?

1
  • 6
    File.exists?() works on files and folders. It doesn't know the difference. Commented Oct 9, 2013 at 19:05

4 Answers 4

322

You are probably trying to create nested directories. Assuming foo does not exist, you will receive no such file or directory error for:

Dir.mkdir 'foo/bar' # => Errno::ENOENT: No such file or directory - 'foo/bar' 

To create nested directories at once, FileUtils is needed:

require 'fileutils' FileUtils.mkdir_p 'foo/bar' # => ["foo/bar"] 

Edit2: you do not have to use FileUtils, you may do system call (update from @mu is too short comment):

> system 'mkdir', '-p', 'foo/bar' # worse version: system 'mkdir -p "foo/bar"' => true 

But that seems (at least to me) as worse approach as you are using external 'tool' which may be unavailable on some systems (although I can hardly imagine system without mkdir, but who knows).

Sign up to request clarification or add additional context in comments.

9 Comments

system 'mkdir', '-p', 'foo/bar' would be a better version of that system call. There's no need for an extra shell process or the usual quoting/escaping/injection nonsense that comes with the single argument version of system.
system will launch /bin/sh to parse the mkdir -p "foo/bar" string and then the shell will run /bin/mkdir. So you're doing extra work (create the command string, launch /bin/sh to pull it apart again) and some of that extra work leaves you open to shell injection attacks (spend some time in the CERT advisories for Ruby and you'll see how common this problem is).
@muistooshort @zrl3dx how is a system call better than fileutils again? I'm on Windows and mkdir_p works just fine without spawning a subshell just to parse mkdir -p which would fail anyway. Glad that fileutils is the first alternative in the answer.
@TWiStErRob: Read my comments again, I said nothing about fileutils or mkdir_p, all I'm saying is that system command, arg1, arg2, ... is better than system command_with_arguments.
@muistooshort ah, sorry, so you're just saying that there's a better way of doing the bad option :)
|
88

Simple way:

directory_name = "name" Dir.mkdir(directory_name) unless File.exist?(directory_name) 

Be aware of the potential for a race condition (time-of-check to time-of-use) which can be a security vulnerability.

6 Comments

One shall use File.directory? rather than File.exists?
Suppose there's a normal file with the same name. You couldn't create a directory in such case.
It also creates a race condition. The file may be created after the check but before creation.
@DonReba How so? Are the methods File.exists? and Dir.mkdir asynchronous?
File.exists? is deprecated in favor of File.exist?
|
35

Another simple way:

Dir.mkdir('tmp/excel') unless Dir.exist?('tmp/excel')

2 Comments

If you want to create nested directories then this doesn't work. For e.g I wanted to create following directory /home/jignesh/reports/test but using this solution raised RUBY (Errno::ENOENT), no such file or directory @ dir_s_mkdir. So the reliable solution is using FileUtils.mkdir_p
This might be unreliable on a powerful server with many simultaneous processes because after Dir.exist? but before Dir.mkdir another process may create the same directory. For this reason I prefer Vidar's suggestion below except that I would prefer to catch only "File Exists" exception.
-8

How about just Dir.mkdir('dir') rescue nil ?

7 Comments

Avoid using rescue in its modifier form.
Care to explain why I should write 5 lines of code instead of just 1? I'd like to see you try.
I already did, and I totally disagree, I think it's silly, so maybe you can enlighten me?
This would catch any exception which is not what you're trying to do and in a real world app would hide problems making maintenance harder. Also, its not a great idea to use exceptions as conditionals, in a hardware sense they run much much slower (likely not really an issue in a modern language but still makes you look inexperienced as a coder).
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.