Crear directorio si no existe con Ruby

156

Estoy tratando de crear un directorio con el siguiente código:

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

Sin embargo, estoy recibiendo este error:

No existe tal archivo o directorio - / Users / Luigi / Desktop / Survey_Final / Archived / Survey / test (Errno :: ENOENT)

¿Por qué este directorio no está siendo creado por la Dir.mkdirdeclaración anterior?

Luigi
fuente
44
File.exists?()Funciona en archivos y carpetas. No sabe la diferencia.
El hombre de hojalata

Respuestas:

263

Probablemente esté intentando crear directorios anidados. Suponiendo fooque no existe, recibirá un no such file or directoryerror por:

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

Para crear directorios anidados a la vez, FileUtilses necesario:

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

Edit2: no tiene que usar FileUtils, puede hacer una llamada al sistema (la actualización de @mu es un comentario demasiado corto):

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

Pero eso parece (al menos para mí) un enfoque peor que el que está utilizando una 'herramienta' externa que puede no estar disponible en algunos sistemas (aunque difícilmente puedo imaginar un sistema sin ellos mkdir, pero quién sabe).

zrl3dx
fuente
55
system 'mkdir', '-p', 'foo/bar'sería una mejor versión de esa systemllamada. No hay necesidad de un proceso de shell adicional o las tonterías habituales de cita / escape / inyección que vienen con la versión de argumento único de system.
mu es demasiado corto el
66
systemse iniciará /bin/shpara analizar la mkdir -p "foo/bar"cadena y luego se ejecutará el shell /bin/mkdir. Entonces, está haciendo un trabajo adicional (cree la cadena de comando, inicie /bin/shpara separarlo nuevamente) y parte de ese trabajo adicional lo deja abierto a ataques de inyección de shell (pase un tiempo en los avisos del CERT para Ruby y verá qué tan común este problema es)
mu es demasiado corto el
1
@muistooshort @ zrl3dx ¿cómo es una systemllamada mejor que fileutilsotra vez? Estoy en Windows y mkdir_pfunciona bien sin generar una subshell solo para analizar, mkdir -plo que fallaría de todos modos. Me alegro de que esa fileutilssea ​​la primera alternativa en la respuesta.
TWiStErRob
1
@TWiStErRob: Lee mis comentarios nuevamente, no dije nada al respecto fileutilso mkdir_p, todo lo que digo es que system command, arg1, arg2, ...es mejor que system command_with_arguments.
mu es demasiado corto el
3
@muistooshort ah, lo siento, así que solo estás diciendo que hay una mejor manera de hacer la mala opción :)
TWiStErRob
71

Manera simple:

directory_name = "name"
Dir.mkdir(directory_name) unless File.exists?(directory_name)
Licysca
fuente
8
Se debe utilizar File.directory? en lugar de File.exists?
Florin Asăvoaie
44
Supongamos que hay un archivo normal con el mismo nombre. No podría crear un directorio en tal caso.
Mikołaj Rozwadowski
3
También crea una condición de carrera. El archivo puede crearse después de la verificación pero antes de la creación.
Don Reba
25

Otra forma simple:

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

Štefan Bartoš
fuente
Si desea crear directorios anidados, entonces esto no funciona. Por ejemplo, quería crear el siguiente directorio /home/jignesh/reports/testpero utilizando esta solución planteada RUBY (Errno::ENOENT), no such file or directory @ dir_s_mkdir. Entonces, la solución confiable está usandoFileUtils.mkdir_p
Jignesh Gohel
-5

¿Qué tal solo Dir.mkdir('dir') rescue nil?

Vidar
fuente
3
Evite usar rescueen su forma modificadora.
Sebastian Palma
1
¿Le gustaría explicar por qué debería escribir 5 líneas de código en lugar de solo 1? Me gustaría verte intentarlo.
Vidar
2
github.com/bbatsov/ruby-style-guide#no-rescue-modifiers eche un vistazo, por favor
Sebastian Palma
1
Ya lo hice, y estoy totalmente en desacuerdo, creo que es una tontería, ¿así que tal vez puedas iluminarme?
Vidar
66
Esto detectaría cualquier excepción que no sea lo que está tratando de hacer y en una aplicación del mundo real ocultaría problemas que dificultarán el mantenimiento. Además, no es una buena idea usar excepciones como condicionales, en un sentido de hardware, se ejecutan mucho más lentamente (probablemente no sea realmente un problema en un lenguaje moderno, pero aún así te hace parecer inexperto como codificador).
Ed_