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?


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).


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)

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')


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?


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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.