Ruby'de dizinleri yinelemeli olarak listelemek için tek satırlık?


98

Ruby'de bir dizi dizin (dosyalar hariç) elde etmenin en hızlı, en optimize, tek satırlık yolu nedir?

Dosyaları dahil etmeye ne dersiniz?


2
En hızlı, en optimize edilmiş ve tek satırlık, okunabilir / korunabilir ile çelişebilir. Ve bunu bir kıyaslama ve hızlı test kullanarak öğrenebilirsiniz.
Teneke Adam

Yanıtlar:


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

Bunun yerine Dir.glob(foo)yazabilirsiniz Dir[foo](ancak Dir.globbir blok da alabilir, bu durumda bir dizi oluşturmak yerine her yolu verir).

Ruby Glob Belgeleri


10
Dir.glob("**/")sembolik bağlantılar istemiyorsanız kullanın
johannes

6
Gizli dosyalar ve dizinler ne olacak?
alediaferia

6
Maç sonuçlarına nokta dosyalarını dahil etmek için File::FNM_DOTMATCHbayrağı kullanın .
x-yuri

2
Teşekkürler @ x-yuri! Btw bayrağı şu şekilde belirtilir:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz

2
Belgeler şu
şekildedir

53

Buradaki çözümlerin hiçbirinin gizli dizinlerle ilgili olmadığına inanıyorum (örneğin, '.test'):

require 'find'
Find.find('.') { |e| puts e if File.directory?(e) }

Find.find('/tmp').collect {|_|_}Bana yardımcı oldu
Alexander Bird


31

Dizin listesi için deneyin

Dir['**/']

Dosya listesi daha zordur, çünkü Unix dizini de bir dosyadır, bu nedenle türü test etmeniz veya döndürülen listedeki diğer girdilerin üst öğesi olan girdileri kaldırmanız gerekir.

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

Ve tüm dosya ve dizinlerin listesi için

Dir['**/*']

"Yalnızca dosyaları" değil, "dosyaları da dahil et" dediğini unutmayın, böylece dizinleri kaldırmanız gerekmez.
eylül

1
@ sepp2k Evet, irb ile oynarken bu bölümü kaçırdım. Ama birisinin benzer bir şey araması ihtimaline karşı bunu burada bırakıyorum :-)
MBO

7

Hızlı tek astar

Yalnızca dizinler

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

Dizinler ve normal dosyalar

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

Saf güzel yakut

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
Yanlış: Dir.glob ("# {DİZİN} / ** / * /"). Map {| dizin | Yoladı.new (dizin)}
Robert Ross

Biri end.select {}.flatten()kısmı açıklayabilir mi? Genel olarak işlevi beğendim. Bu bir dizi dizisi yaratacak gibi görünüyor? Parçayı şu şekilde yapmak mümkün olabilir miydi elseif: rec_path(child, file) << child.to_sBöylece onu bir diziye atayabilir ve bir dizi dizesi elde edebilirsiniz? Teşekkürler!
MCP

7

Buradaki diğer cevaplarda da belirtildiği gibi kullanabilirsiniz Dir.glob. Klasörlerin içinde birçok garip karakter olabileceğini ve glob argümanlarının kalıp olduğunu, bu nedenle bazı karakterlerin özel anlamları olduğunu unutmayın. Bu nedenle, aşağıdaki gibi bir şey yapmak güvenli değildir:

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

Bunun yerine şunları yapın:

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

2

PHP veya diğer dillerde bir dizinin içeriğini ve tüm alt dizinlerini almak için bazı satırlar kod yazmanız gerekir, ancak Ruby'de bu 2 satır alır:

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

bu, geçerli dizinin ve tüm alt dizinlerinin içeriğini yazdıracaktır.

Veya daha kısa, ’**’gösterimi kullanabilirsiniz :

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

Aynı sonucu almak için PHP veya Java'da kaç satır yazacaksınız?


14
Kaynak belirtilmeden, mustap.com/rubyzone_post_162_recursive-directory-listing adresinden doğrudan kopyalayıp yapıştırmak için olumsuz oy verildi ...
eckza

@kivetros Bağlantının arşivlenmiş sürümünü eklemek için yanıtı düzenledim :-)
onebree

0

Tek satırlık bir çözüm olmasa da, Ruby çağrılarını kullanarak bunu yapmanın en iyi yolu olduğunu düşünüyorum.

Önce tüm dosyaları yinelemeli olarak
silin İkinci olarak tüm boş dizinleri silin

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

3
Dosyaları / dizinleri silmek istemiyor.
Darek Nędza

Bunu tek bir satırdaki her iki dosya + dizin için nasıl yapabilirim?
vipin8169

0

İşte bir Rails proje dizininin dinamik keşfini Dir.glob ile birleştiren bir örnek:

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

Bunu denedim >> config.assets.paths << Rails.root.join("app", "assets", "*"), ancak yine de varlıklar klasörünün içindeki alt klasörleri ve dosyaları Rails.application.config.assets.paths
göremedim

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

noktalar sıfır döndürür, kompakt kullanın


1
Bu çok zarif değil ve öyle olması için birkaç satırda daha olması gerekiyor
onebree
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.