Erstellen Sie ein Verzeichnis, wenn es mit Ruby nicht vorhanden ist


156

Ich versuche ein Verzeichnis mit dem folgenden Code zu erstellen:

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

Ich erhalte jedoch diesen Fehler:

Keine solche Datei oder kein solches Verzeichnis - / Users / Luigi / Desktop / Survey_Final / Archived / Survey / test (Errno :: ENOENT)

Warum wird dieses Verzeichnis nicht durch die Dir.mkdirobige Anweisung erstellt?


4
File.exists?()funktioniert mit Dateien und Ordnern. Es kennt den Unterschied nicht.
der Blechmann

Antworten:


263

Sie versuchen wahrscheinlich, verschachtelte Verzeichnisse zu erstellen. Vorausgesetzt, fooes existiert nicht, erhalten Sie eine no such file or directoryFehlermeldung für:

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

Um verschachtelte Verzeichnisse gleichzeitig zu erstellen, FileUtilsist Folgendes erforderlich:

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

Edit2: Sie müssen nicht verwenden FileUtils, Sie können Systemaufruf ausführen (Update von @mu ist zu kurzer Kommentar):

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

Aber das scheint (zumindest für mich) ein ebenso schlechterer Ansatz zu sein, als wenn Sie ein externes 'Tool' verwenden, das auf einigen Systemen möglicherweise nicht verfügbar ist (obwohl ich mir ein System ohne kaum vorstellen kann mkdir, aber wer weiß).


5
system 'mkdir', '-p', 'foo/bar'wäre eine bessere Version dieses systemAufrufs. Es ist kein zusätzlicher Shell-Prozess oder der übliche Quoting / Escape / Injection-Unsinn erforderlich, der mit der Single-Argument-Version von geliefert wird system.
Mu ist zu kurz

6
systemwird gestartet /bin/sh, um die mkdir -p "foo/bar"Zeichenfolge zu analysieren, und dann wird die Shell ausgeführt /bin/mkdir. Sie erledigen also zusätzliche Arbeit (erstellen Sie die Befehlszeichenfolge, starten Sie /bin/sh, um sie wieder auseinander zu ziehen), und einige dieser zusätzlichen Arbeiten lassen Sie für Shell-Injection-Angriffe offen (verbringen Sie einige Zeit in den CERT-Hinweisen für Ruby, und Sie werden sehen, wie häufig Dieses Problem ist).
Mu ist zu kurz

1
@muistooshort @ zrl3dx Wie ist ein systemAnruf besser als fileutilswieder? Ich bin unter Windows und mkdir_pfunktioniert einwandfrei, ohne eine Subshell zu erzeugen, nur um zu analysieren, mkdir -pwas sowieso fehlschlagen würde. Ich bin froh, dass dies fileutilsdie erste Alternative in der Antwort ist.
TWiStErRob

1
@TWiStErRob: Lies meine Kommentare noch einmal, ich sagte nichts über fileutilsoder mkdir_p, alles was ich sage ist, dass system command, arg1, arg2, ...es besser ist als system command_with_arguments.
Mu ist zu kurz

3
@ Muistooshort ah, sorry, also sagst du nur, dass es einen besseren Weg gibt, die schlechte Option zu machen :)
TWiStErRob

71

Einfacher Weg:

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

8
Man soll File.directory verwenden? eher als File.exists?
Florin Asăvoaie

4
Angenommen, es gibt eine normale Datei mit demselben Namen. In einem solchen Fall konnten Sie kein Verzeichnis erstellen.
Mikołaj Rozwadowski

3
Es schafft auch eine Rennbedingung. Die Datei kann nach der Prüfung, jedoch vor der Erstellung erstellt werden.
Don Reba

25

Ein anderer einfacher Weg:

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


Wenn Sie verschachtelte Verzeichnisse erstellen möchten, funktioniert dies nicht. Zum Beispiel wollte ich folgendes Verzeichnis erstellen, /home/jignesh/reports/testaber mit dieser Lösung ausgelöst RUBY (Errno::ENOENT), no such file or directory @ dir_s_mkdir. Die zuverlässige Lösung ist alsoFileUtils.mkdir_p
Jignesh Gohel

-5

Wie wäre es einfach Dir.mkdir('dir') rescue nil?


3
Vermeiden Sie die Verwendung rescuein der Modifikatorform.
Sebastian Palma

1
Möchten Sie erklären, warum ich 5 Codezeilen anstelle von nur 1 schreiben sollte? Ich würde dich gerne versuchen sehen.
Vidar


1
Ich habe es bereits getan, und ich bin völlig anderer Meinung, ich finde es albern, also kannst du mich vielleicht aufklären?
Vidar

6
Dies würde jede Ausnahme einfangen, die nicht das ist, was Sie versuchen, und in einer realen App würde es Probleme verbergen, die die Wartung erschweren. Es ist auch keine gute Idee, Ausnahmen als Bedingungen zu verwenden, da sie im Hardware-Sinne viel langsamer laufen (wahrscheinlich kein Problem in einer modernen Sprache, aber Sie als Programmierer immer noch unerfahren aussehen lassen).
Ed_
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.