One-liner para listar diretórios recursivamente em Ruby?


96

Qual é a maneira mais rápida e otimizada de uma linha para obter um array de diretórios (excluindo arquivos) em Ruby?

Que tal incluir arquivos?


2
Mais rápido, mais otimizado e de uma linha pode estar em conflito com legível / sustentável. E você pode descobrir isso usando um benchmark e um teste rápido.
The Tin Man de

Respostas:


180
Dir.glob("**/*/") # for directories
Dir.glob("**/*") # for all files

Em vez de, Dir.glob(foo)você também pode escrever Dir[foo](no entanto, Dir.globtambém pode pegar um bloco, caso em que produzirá cada caminho em vez de criar uma matriz).

Ruby Glob Docs


10
use a Dir.glob("**/")menos que você também queira links simbólicos
johannes,

6
E quanto a arquivos e diretórios ocultos?
alediaferia

6
Para incluir dotfiles nos resultados da partida, use o File::FNM_DOTMATCHsinalizador.
x-yuri

2
Obrigado @ x-yuri! O sinalizador btw é especificado assim:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz



31

Para uma lista de diretórios, tente

Dir['**/']

Lista de arquivos é mais difícil, porque no diretório Unix também é um arquivo, então você precisa testar o tipo ou remover as entradas da lista retornada que é pai de outras entradas.

Dir['**/*'].reject {|fn| File.directory?(fn) }

E para a lista de todos os arquivos e diretórios simplesmente

Dir['**/*']

Observe que ele disse "também incluir arquivos", não "apenas arquivos", portanto, você não precisa remover os diretórios.
sepp2k,

1
@ sepp2k Sim, eu perdi essa parte quando estava jogando com o irb. Mas deixo aqui para o caso de alguém pesquisar algo semelhante :-)
MBO

7

Fast one liner

Apenas diretórios

`find -type d`.split("\n")

Diretórios e arquivos normais

`find -type d -or -type f`.split("\n")`

Rubi lindo puro

require "pathname"

def rec_path(path, file= false)
  puts path
  path.children.collect do |child|
    if file and child.file?
      child
    elsif child.directory?
      rec_path(child, file) + [child]
    end
  end.select { |x| x }.flatten(1)
end

# only directories
rec_path(Pathname.new(dir), false)
# directories and normal files
rec_path(Pathname.new(dir), true)

1
Falso: Dir.glob ("# {DIRETÓRIO} / ** / * /"). Map {| diretório | Pathname.new (diretório)}
Robert Ross

Alguém pode explicar a end.select {}.flatten()parte? Eu gosto da função geral. Parece que vai criar um array de arrays? Seria possível fazer a elseifparte com: rec_path(child, file) << child.to_spara que você pudesse atribuí-la a um array e obter um array de strings? Obrigado!
MCP

7

Conforme observado em outras respostas aqui, você pode usar Dir.glob. Lembre-se de que as pastas podem conter muitos caracteres estranhos e os argumentos glob são padrões, portanto, alguns caracteres têm significados especiais. Como tal, não é seguro fazer algo como o seguinte:

Dir.glob("#{folder}/**/*")

Em vez disso, faça:

Dir.chdir(folder) { Dir.glob("**/*").map {|path| File.expand_path(path) } }

2

Em PHP ou outras linguagens, para obter o conteúdo de um diretório e todos os seus subdiretórios, você deve escrever algumas linhas de código, mas em Ruby são necessárias 2 linhas:

require 'find'
Find.find('./') do |f| p f end

isso imprimirá o conteúdo do diretório atual e todos os seus subdiretórios.

Ou mais curto, você pode usar a ’**’notação:

p Dir['**/*.*']

Quantas linhas você escreverá em PHP ou em Java para obter o mesmo resultado?


13
Votos negativos para copiar e colar diretamente de mustap.com/rubyzone_post_162_recursive-directory-listing sem citar a fonte ...
eckza

@kivetros Editei a resposta para incluir a versão arquivada do link :-)
onebree

0

Embora não seja uma solução de uma linha, acho que essa é a melhor maneira de fazer isso usando chamadas de ruby.

Primeiro apague todos os arquivos recursivamente
Segundo apague todos os diretórios vazios

Dir.glob("./logs/**/*").each { |file| File.delete(file) if File.file? file }
Dir.glob("./logs/**/*/").each { |directory| Dir.delete(directory) }

3
Ele / ela não deseja excluir arquivos / diretórios.
Darek Nędza

Como fazer isso para os dois arquivos + diretório em uma única linha?
vipin8169

0

Aqui está um exemplo que combina a descoberta dinâmica de um diretório de projeto Rails com Dir.glob:

dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))

Eu tentei isso >> config.assets.paths << Rails.root.join("app", "assets", "*"), mas ainda não conseguia ver as subpastas e arquivos dentro da pasta de ativos porRails.application.config.assets.paths
vipin8169

-1
Dir.open(Dir.pwd).map { |h| (File.file?(h) ? "#{h} - file" : "#{h} - folder") if h[0] != '.' }

pontos retornam nulo, use compacto


1
Isso não é muito elegante e precisaria estar em mais algumas linhas para ser assim
onebree
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.