Jednowierszowy do rekurencyjnej listy katalogów w Rubim?

96

Jaki jest najszybszy, najbardziej zoptymalizowany, jednowierszowy sposób na uzyskanie tablicy katalogów (z wyłączeniem plików) w Rubim?

A co z dołączaniem plików?

Lance Pollard
źródło
2
Najszybsza, najbardziej zoptymalizowana i jednowierszowa może być sprzeczna z czytelnością / możliwością konserwacji. Możesz się tego dowiedzieć za pomocą testu porównawczego i szybkich testów.
Tin Man

Odpowiedzi:

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

Zamiast tego Dir.glob(foo)możesz także pisać Dir[foo](ale Dir.globmoże również wziąć blok, w takim przypadku zwróci każdą ścieżkę zamiast tworzenia tablicy).

Ruby Glob Docs

sepp2k
źródło
10
używaj, Dir.glob("**/")chyba że chcesz również linki symboliczne
johannes
6
A co z ukrytymi plikami i katalogami?
alediaferia
6
Aby uwzględnić dotfiles w wynikach dopasowania, użyj File::FNM_DOTMATCHflagi.
x-yuri
2
Dzięki @ x-yuri! Flaga btw jest określona w następujący sposób:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz
2
Oto dokumentacja: ruby-doc.org/core-2.2.0/Dir.html#method-c-glob
stephen.hanson
53

Uważam, że żadne z rozwiązań tutaj nie dotyczy ukrytych katalogów (np. „.Test”):

require 'find'
Find.find('.') { |e| puts e if File.directory?(e) }
FelipeC
źródło
Find.find('/tmp').collect {|_|_}Był dla mnie pomocny
Alexander Bird,
Uważaj na Find, nie śledzi
linków
31

Aby uzyskać listę katalogów, spróbuj

Dir['**/']

Lista plików jest trudniejsza, ponieważ w katalogu Unix znajduje się również plik, więc musisz przetestować typ lub usunąć wpisy z listy zwracanej, która jest rodzicem innych wpisów.

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

I po prostu lista wszystkich plików i katalogów

Dir['**/*']
MBO
źródło
Zauważ, że powiedział „dołączaj również pliki”, a nie „tylko pliki”, więc nie musisz usuwać katalogów.
wrzesień
1
@ sepp2k Tak, tęskniłem za tą częścią, kiedy grałem z irbem. Ale zostawiam to tutaj na wypadek, gdyby ktoś szukał czegoś podobnego :-)
MBO
7

Szybki jeden wkład

Tylko katalogi

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

Katalogi i zwykłe pliki

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

Czysty piękny rubin

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)
johannes
źródło
1
Fałsz: Dir.glob ("# {KATALOG} / ** / * /"). Map {| katalog | Pathname.new (katalog)}
Robert Ross
Czy ktoś może wyjaśnić tę end.select {}.flatten()część? Ogólnie podoba mi się ta funkcja. Wygląda na to, że utworzy tablicę tablic? Czy byłoby możliwe wykonanie tej elseifczęści za pomocą: rec_path(child, file) << child.to_stak, aby można było przypisać ją do tablicy i uzyskać tablicę ciągów? Dzięki!
MCP,
7

Jak wspomniano w innych odpowiedziach tutaj, możesz użyć Dir.glob. Należy pamiętać, że foldery mogą zawierać wiele dziwnych znaków, a argumenty glob są wzorcami, więc niektóre znaki mają specjalne znaczenie. W związku z tym wykonanie następujących czynności jest niebezpieczne:

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

Zamiast tego zrób:

Dir.chdir(folder) { Dir.glob("**/*").map {|path| File.expand_path(path) } }
troelskn
źródło
2

W PHP lub innych językach, aby uzyskać zawartość katalogu i wszystkich jego podkatalogów, musisz napisać kilka wierszy kodu, ale w Rubim zajmuje to 2 wiersze:

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

spowoduje to wydrukowanie zawartości bieżącego katalogu i wszystkich jego podkatalogów.

Lub krócej, możesz użyć ’**’notacji:

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

Ile wierszy napiszesz w PHP lub Javie, aby uzyskać ten sam wynik?

Ramesh
źródło
13
Głos w dół za bezpośrednie kopiowanie-wklejanie z mustap.com/rubyzone_post_162_recursive-directory-listing bez cytowania źródła ...
eckza
@kivetros Zmieniłem odpowiedź, dodając zarchiwizowaną wersję linku :-)
onebree
0

Chociaż nie jest to rozwiązanie jednokreskowe, myślę, że jest to najlepszy sposób na zrobienie tego za pomocą wywołań ruby.

Najpierw usuń wszystkie pliki rekurencyjnie. Następnie
usuń wszystkie puste katalogi

Dir.glob("./logs/**/*").each { |file| File.delete(file) if File.file? file }
Dir.glob("./logs/**/*/").each { |directory| Dir.delete(directory) }
HomeTurf
źródło
3
On / ona nie chce usuwać plików / katalogów.
Darek Nędza
Jak to zrobić dla obu plików + katalogu w jednej linii?
vipin8169
0

Oto przykład, który łączy dynamiczne wykrywanie katalogu projektu Rails z Dir.glob:

dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))
shacker
źródło
Próbowałem tego >> config.assets.paths << Rails.root.join("app", "assets", "*"), ale nadal nie widziałem podfolderów i plików w folderze zasobów przezRails.application.config.assets.paths
vipin8169
-1
Dir.open(Dir.pwd).map { |h| (File.file?(h) ? "#{h} - file" : "#{h} - folder") if h[0] != '.' }

kropki zwracają zero, użyj compact

ruvan
źródło
1
To nie jest zbyt eleganckie i aby tak było, musiałoby być w kilku kolejnych liniach
onebree