Criar diretório se ele não existir com Ruby

156

Estou tentando criar um diretório com o seguinte código:

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

No entanto, estou recebendo este erro:

Esse arquivo ou diretório não existe - / Usuários / Luigi / Desktop / Survey_Final / Arquivado / Pesquisa / teste (Errno :: ENOENT)

Por que esse diretório não está sendo criado pela Dir.mkdirdeclaração acima?

Luigi
fonte
4
File.exists?()funciona em arquivos e pastas. Não sabe a diferença.
the Tin Man

Respostas:

263

Você provavelmente está tentando criar diretórios aninhados. Supondo fooque não exista, você receberá um no such file or directoryerro para:

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

Para criar diretórios aninhados de uma só vez, FileUtilsé necessário:

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

Edit2: você não precisa usar FileUtils, pode fazer uma chamada do sistema (a atualização do @mu é um comentário muito curto):

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

Mas isso parece (pelo menos para mim) uma abordagem pior do que você está usando uma 'ferramenta' externa que pode não estar disponível em alguns sistemas (embora eu mal possa imaginar o sistema sem mkdir, mas quem sabe).

zrl3dx
fonte
5
system 'mkdir', '-p', 'foo/bar'seria uma versão melhor dessa systemligação. Não há necessidade de um processo extra de shell ou do absurdo comum de citação / escape / injeção que vem com a versão de argumento único system.
mu é muito curto
6
systemserá iniciado /bin/shpara analisar a mkdir -p "foo/bar"string e, em seguida, o shell será executado /bin/mkdir. Então você está fazendo um trabalho extra (crie a cadeia de comando, inicie /bin/shpara separá-la novamente) e parte desse trabalho extra o deixará aberto a ataques de injeção de shell (passe algum tempo nos avisos do CERT para Ruby e verá como é comum esse problema é).
mu é muito curto
1
@muistooshort @ zrl3dx como é systemmelhor ligar de fileutilsnovo? Estou no Windows e mkdir_pfunciona muito bem sem gerar um subshell apenas para analisar o mkdir -pque falharia de qualquer maneira. Ainda bem que fileutilsé a primeira alternativa na resposta.
TWIStErRob
1
@TWiStErRob: Leia meus comentários novamente, não falei nada sobre fileutilsou mkdir_ptudo o que estou dizendo é que system command, arg1, arg2, ...é melhor do que isso system command_with_arguments.
mu é muito curto
3
@muistooshort ah, desculpe, então você está apenas dizendo que há uma maneira melhor de fazer a opção ruim :)
TWiStErRob
71

Maneira simples:

directory_name = "name"
Dir.mkdir(directory_name) unless File.exists?(directory_name)
Licysca
fonte
8
Um deve usar File.directory? em vez de File.exists?
Florin Asăvoaie
4
Suponha que exista um arquivo normal com o mesmo nome. Você não pode criar um diretório nesse caso.
Mikołaj Rozwadowski
3
Ele também cria uma condição de corrida. O arquivo pode ser criado após a verificação, mas antes da criação.
Don Reba
25

Outra maneira simples:

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

Štefan Bartoš
fonte
Se você deseja criar diretórios aninhados, isso não funciona. Por exemplo, eu queria criar o seguinte diretório, /home/jignesh/reports/testmas usando esta solução levantada RUBY (Errno::ENOENT), no such file or directory @ dir_s_mkdir. Portanto, a solução confiável está usandoFileUtils.mkdir_p
Jignesh Gohel
-5

Que tal apenas Dir.mkdir('dir') rescue nil?

Vidar
fonte
3
Evite usar rescueem sua forma modificadora.
Sebastian Palma
1
Gostaria de explicar por que eu deveria escrever 5 linhas de código em vez de apenas 1? Eu gostaria de ver você tentar.
Vidar 22/01
2
github.com/bbatsov/ruby-style-guide#no-rescue-modifiers dê uma olhada, por favor
Sebastian Palma
1
Eu já fiz, e discordo totalmente, acho que é bobagem, então talvez você possa me esclarecer?
Vidar
6
Isso capturaria qualquer exceção que não seja o que você está tentando fazer e, em um aplicativo do mundo real, ocultaria problemas que dificultariam a manutenção. Além disso, não é uma boa idéia usar exceções como condicionais, no sentido de hardware elas são muito mais lentas (provavelmente não é realmente um problema em uma linguagem moderna, mas ainda fazem você parecer inexperiente como codificador).
18717 Ed