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?

Luigi
quelle
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ß).

zrl3dx
quelle
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)
Licysca
quelle
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')

Štefan Bartoš
quelle
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?

Vidar
quelle
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
2
github.com/bbatsov/ruby-style-guide#no-rescue-modifiers schauen Sie bitte
Sebastian Palma
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_