One-liner untuk mendaftar direktori secara rekursif di Ruby?

96

Apa cara tercepat, paling optimal, satu-liner untuk mendapatkan array direktori (tidak termasuk file) di Ruby?

Bagaimana dengan menyertakan file?

Lance Pollard
sumber
2
Tercepat, paling optimal, dan satu baris dapat bertentangan dengan dapat dibaca / dipelihara. Dan, Anda dapat mengetahuinya dengan menggunakan tolok ukur dan pengujian cepat.
Tin Man

Jawaban:

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

Selain Dir.glob(foo)Anda juga dapat menulis Dir[foo](namun Dir.globjuga dapat mengambil blok, dalam hal ini akan menghasilkan setiap jalur alih-alih membuat larik).

Ruby Glob Docs

sepp2k.dll
sumber
10
gunakan Dir.glob("**/")kecuali Anda juga ingin symlinks
johannes
6
Bagaimana dengan file dan direktori tersembunyi?
alediaferia
6
Untuk memasukkan dotfiles dalam hasil pertandingan, gunakan File::FNM_DOTMATCHbendera.
x-yuri
2
Terima kasih @ x-yuri! Bendera btw ditentukan seperti ini:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz
2
Berikut dokumentasinya: ruby-doc.org/core-2.2.0/Dir.html#method-c-glob
stephen.hanson
53

Saya yakin tidak ada solusi di sini yang berhubungan dengan direktori tersembunyi (misalnya '.test'):

require 'find'
Find.find('.') { |e| puts e if File.directory?(e) }
FelipeC
sumber
Find.find('/tmp').collect {|_|_}Sangat membantu bagi saya
Alexander Bird
Hati-hati dengan Find, itu tidak mengikuti symlinks: stackoverflow.com/questions/3974087/…
leebutts
31

Untuk daftar direktori coba

Dir['**/']

Daftar file lebih sulit, karena di direktori Unix juga ada file, jadi Anda perlu menguji jenis atau menghapus entri dari daftar yang dikembalikan yang merupakan induk dari entri lain.

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

Dan untuk daftar semua file dan direktori secara sederhana

Dir['**/*']
MBO
sumber
Perhatikan bahwa dia berkata "juga termasuk file", bukan "hanya file" jadi Anda tidak perlu menghapus direktori.
sepp2k
1
@ sepp2k Ya, saya melewatkan bagian ini ketika saya bermain dengan irb. Tapi saya tinggalkan ini di sini kalau-kalau seseorang mungkin mencari sesuatu yang mirip :-)
MBO
7

Cepat satu kapal

Hanya direktori

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

Direktori dan file normal

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

Ruby yang indah dan murni

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
sumber
1
Salah: Dir.glob ("# {DIRECTORY} / ** / * /"). Map {| direktori | Pathname.new (direktori)}
Robert Ross
Adakah yang bisa menjelaskan end.select {}.flatten()bagian itu? Saya suka fungsinya secara keseluruhan. Sepertinya itu akan membuat array array? Apakah mungkin untuk melakukan elseifbagian tersebut dengan: rec_path(child, file) << child.to_ssehingga Anda bisa menugaskannya ke sebuah array dan mendapatkan sebuah array string? Terima kasih!
MCP
7

Seperti yang disebutkan dalam jawaban lain di sini, Anda dapat menggunakan Dir.glob. Perlu diingat bahwa folder dapat memiliki banyak karakter aneh di dalamnya, dan argumen glob adalah pola, jadi beberapa karakter memiliki arti khusus. Karena itu, tidak aman untuk melakukan sesuatu seperti berikut ini:

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

Sebaliknya lakukan:

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

Di PHP atau bahasa lain untuk mendapatkan konten dari sebuah direktori dan semua subdirektorinya, Anda harus menulis beberapa baris kode, tetapi di Ruby dibutuhkan 2 baris:

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

ini akan mencetak konten dari direktori saat ini dan semua subdirektorinya.

Atau lebih pendek, Anda dapat menggunakan ’**’notasi:

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

Berapa banyak baris yang akan Anda tulis dalam PHP atau Java untuk mendapatkan hasil yang sama?

Ramesh
sumber
13
Tidak memilih untuk langsung menyalin-tempel dari mustap.com/rubyzone_post_162_recursive-directory-listing tanpa mengutip sumbernya ...
eckza
@kivetros Saya mengedit jawabannya untuk menyertakan versi link yang diarsipkan :-)
onebree
0

Meskipun bukan solusi satu baris, saya rasa ini adalah cara terbaik untuk melakukannya menggunakan panggilan ruby.

Pertama hapus semua file secara rekursif
Kedua hapus semua direktori kosong

Dir.glob("./logs/**/*").each { |file| File.delete(file) if File.file? file }
Dir.glob("./logs/**/*/").each { |directory| Dir.delete(directory) }
HomeTurf
sumber
3
Dia tidak ingin menghapus file / direktori.
Darek Nędza
Bagaimana melakukan ini untuk kedua file + direktori dalam satu baris?
vipin8169
0

Berikut adalah contoh yang menggabungkan penemuan dinamis dari direktori proyek Rails dengan Dir.glob:

dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))
shacker
sumber
Saya mencoba ini >> config.assets.paths << Rails.root.join("app", "assets", "*"), tetapi masih tidak dapat melihat sub-folder dan file di dalam folder aset olehRails.application.config.assets.paths
vipin8169
-1
Dir.open(Dir.pwd).map { |h| (File.file?(h) ? "#{h} - file" : "#{h} - folder") if h[0] != '.' }

titik kembali nihil, gunakan kompak

ruvan
sumber
1
Ini tidak terlalu elegan, dan perlu ada beberapa baris lagi untuk menjadi begitu
onebree