Создать каталог, если он не существует с Ruby

156

Я пытаюсь создать каталог со следующим кодом:

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

Тем не менее, я получаю эту ошибку:

Нет такого файла или каталога - / Users / Luigi / Desktop / Survey_Final / Archived / Survey / test (Errno :: ENOENT)

Почему этот каталог не создается приведенным Dir.mkdirвыше заявлением?

Луиджи
источник
4
File.exists?()работает с файлами и папками. Это не знает разницу.
Жестянщик

Ответы:

263

Вы, вероятно, пытаетесь создать вложенные каталоги. Предполагая, fooчто не существует, вы получите no such file or directoryошибку для:

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

Для одновременного создания вложенных каталогов FileUtilsнеобходимо:

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

Edit2: вам не нужно использовать FileUtils, вы можете сделать системный вызов (обновление от @mu слишком короткий комментарий):

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

Но это кажется (по крайней мере, мне) более худшим подходом, чем использование внешнего «инструмента», который может быть недоступен в некоторых системах (хотя я вряд ли могу представить систему без mkdir, но кто знает).

zrl3dx
источник
5
system 'mkdir', '-p', 'foo/bar'будет лучшей версией этого systemзвонка. Нет необходимости в дополнительном процессе оболочки или обычной ерунде, заключающейся в кавычках / экранировании / инъекциях, которая поставляется с версией с одним аргументом system.
мю слишком коротка
6
systemзапустит /bin/shдля разбора mkdir -p "foo/bar"строки, а затем будет запущена оболочка /bin/mkdir. Таким образом, вы выполняете дополнительную работу (создаете командную строку, запускаете /bin/shее снова для разделения), и часть этой дополнительной работы оставляет вас открытыми для атак с использованием инъекций в оболочку (потратьте некоторое время на рекомендации CERT для Ruby, и вы увидите, как часто эта проблема есть).
мю слишком коротка
1
@muistooshort @ zrl3dx как systemзвонок лучше, чем fileutilsснова? Я работаю на Windows и mkdir_pпрекрасно работаю, не вызывая подоболочки, просто для анализа, mkdir -pкоторый в любом случае потерпит неудачу. Рад, что fileutilsэто первая альтернатива в ответе.
TWiStErRob
1
@TWiStErRob: Прочитайте мои комментарии еще раз, я ничего не сказал fileutilsили mkdir_p, все, что я говорю, это то, что system command, arg1, arg2, ...лучше, чем system command_with_arguments.
мю слишком коротка
3
@muistooshort ах, извините, так вы просто говорите, что есть лучший способ сделать плохой вариант :)
TWiStErRob
71

Простой способ:

directory_name = "name"
Dir.mkdir(directory_name) unless File.exists?(directory_name)
Licysca
источник
8
Нужно использовать File.directory? а не File.exists?
Florin Asăvoaie
4
Предположим, есть обычный файл с таким же именем. Вы не можете создать каталог в таком случае.
Миколай Розвадовский
3
Это также создает условия гонки. Файл может быть создан после проверки, но до создания.
Дон Реба
25

Еще один простой способ:

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

Штефан Бартош
источник
Если вы хотите создать вложенные каталоги, тогда это не сработает. Например, я хотел создать следующий каталог, /home/jignesh/reports/testно с помощью этого решения поднял RUBY (Errno::ENOENT), no such file or directory @ dir_s_mkdir. Таким образом, надежное решение используетFileUtils.mkdir_p
Jignesh Gohel
-5

Как насчет просто Dir.mkdir('dir') rescue nil?

Видар
источник
3
Избегайте использования rescueв его форме модификатора.
Себастьян Пальма
1
Хотите объяснить, почему я должен написать 5 строк кода вместо 1? Я бы хотел, чтобы ты попробовал.
Видар
2
github.com/bbatsov/ruby-style-guide#no-rescue-modifiers , пожалуйста, посмотрите
Себастьян Пальма
1
Я уже сделал, и я совершенно не согласен, я думаю, что это глупо, так что, может быть, вы можете просветить меня?
Видар
6
Это поймает любое исключение, которое вы не пытаетесь сделать, и в реальном мире приложение будет скрывать проблемы, усложняющие обслуживание. Кроме того, не очень хорошая идея использовать исключения в качестве условных выражений, в аппаратном смысле они работают намного медленнее (вероятно, это не проблема современного языка, но все равно заставляет вас выглядеть неопытным как программист).
Ed_