Una riga per elencare in modo ricorsivo le directory in Ruby?


96

Qual è il modo più veloce e ottimizzato per ottenere un array di directory (esclusi i file) in Ruby?

Che ne dici di includere i file?


2
Il più veloce, il più ottimizzato e il one-liner possono essere in contrasto con leggibile / gestibile. E potresti scoprirlo usando un benchmark e test rapidi.
Tin Man

Risposte:


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

Invece di Dir.glob(foo)puoi anche scrivere Dir[foo](tuttavia Dir.globpuò anche prendere un blocco, nel qual caso produrrà ogni percorso invece di creare un array).

Ruby Glob Docs


10
usa a Dir.glob("**/")meno che tu non voglia anche link simbolici
johannes

6
E i file e le directory nascosti?
alediaferia

6
Per includere dotfile nei risultati della partita, usa il File::FNM_DOTMATCHflag.
x-yuri

2
Grazie @ x-yuri! La bandiera tra l'altro è specificata in questo modo:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz



31

Per l'elenco delle directory prova

Dir['**/']

L'elenco dei file è più difficile, perché nella directory Unix c'è anche un file, quindi è necessario testare il tipo o rimuovere le voci dall'elenco restituito che è genitore di altre voci.

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

E per l'elenco di tutti i file e le directory semplicemente

Dir['**/*']

Nota che ha detto "includi anche file", non "solo file", quindi non è necessario rimuovere le directory.
sepp2k

1
@ sepp2k Sì, mi sono perso questa parte quando suonavo con irb. Ma lo lascio qui nel caso qualcuno possa cercare qualcosa di simile :-)
MBO

7

Fast one liner

Solo directory

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

Directory e file normali

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

Rubino puro e bellissimo

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 ("# {DIRECTORY} / ** / * /"). Map {| directory | Pathname.new (directory)}
Robert Ross

Qualcuno può spiegare la end.select {}.flatten()parte? Mi piace la funzione in generale. Sembra che creerà un array di array? Sarebbe possibile eseguire la elseifparte con: in rec_path(child, file) << child.to_smodo da poterla assegnare a un array e ottenere un array di stringhe? Grazie!
MCP

7

Come notato in altre risposte qui, puoi usare Dir.glob. Tieni presente che le cartelle possono contenere molti caratteri strani e gli argomenti glob sono modelli, quindi alcuni caratteri hanno significati speciali. In quanto tale, non è sicuro fare qualcosa di simile a quanto segue:

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

Invece fai:

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

2

In PHP o in altri linguaggi per ottenere il contenuto di una directory e tutte le sue sottodirectory, devi scrivere alcune righe di codice, ma in Ruby ci vogliono 2 righe:

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

questo stamperà il contenuto della directory corrente e tutte le sue sottodirectory.

O più breve, puoi usare la ’**’notazione:

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

Quante righe scriverai in PHP o in Java per ottenere lo stesso risultato?


13
Downvoted per copia-incolla direttamente da mustap.com/rubyzone_post_162_recursive-directory-listing senza citare la fonte ...
eckza

@kivetros Ho modificato la risposta per includere la versione archiviata del link :-)
onebree

0

Sebbene non sia una soluzione a una riga, penso che questo sia il modo migliore per farlo usando le chiamate ruby.

Prima cancella tutti i file in modo ricorsivo
Secondo cancella tutte le directory vuote

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

3
Non vuole eliminare file / directory.
Darek Nędza

Come farlo per entrambi i file + directory in una singola riga?
vipin8169

0

Ecco un esempio che combina il rilevamento dinamico di una directory di progetto Rails con Dir.glob:

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

Ho provato questo >> config.assets.paths << Rails.root.join("app", "assets", "*"), ma ancora non riuscivo a vedere le sottocartelle e i file all'interno della cartella delle risorse daRails.application.config.assets.paths
vipin8169

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

i punti restituiscono zero, usa compatto


1
Questo non è troppo elegante e dovrebbe essere su qualche riga in più per essere così
onebree
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.