Một lớp lót để liệt kê đệ quy các thư mục trong Ruby?


96

Cách nhanh nhất, tối ưu nhất, một lớp để lấy một mảng thư mục (không bao gồm tệp) trong Ruby là gì?

Làm thế nào về bao gồm các tệp?


2
Nhanh nhất, tối ưu nhất và một lớp lót có thể trái ngược với khả năng đọc / bảo trì. Và, bạn có thể tìm ra điều này bằng cách sử dụng điểm chuẩn và thử nghiệm nhanh.
Tin Man

Câu trả lời:


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

Thay vào đó, Dir.glob(foo)bạn cũng có thể viết Dir[foo](tuy nhiên Dir.globcũng có thể lấy một khối, trong trường hợp đó, nó sẽ mang lại mỗi đường dẫn thay vì tạo một mảng).

Tài liệu Ruby Glob


10
sử dụng Dir.glob("**/")trừ khi bạn cũng muốn liên kết tượng trưng
Johannes

6
Điều gì về các tệp và thư mục ẩn?
alediaferia,

6
Để đưa các tệp chấm vào kết quả trận đấu, hãy sử dụng File::FNM_DOTMATCHcờ.
x-yuri

2
Cảm ơn @ x-yuri! Lá cờ btw được quy định như thế này:Dir.glob("**/*", File::FNM_DOTMATCH)
VLZ

2
Đây là tài liệu hướng dẫn: ruby-doc.org/core-2.2.0/Dir.html#method-c-glob
stephen.hanson

53

Tôi tin rằng không có giải pháp nào ở đây giải quyết các thư mục ẩn (ví dụ: '.test'):

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

Find.find('/tmp').collect {|_|_}Là hữu ích đối với tôi
Alexander Bird

Hãy cẩn thận với Tìm, nó không tuân theo các liên kết tượng trưng: stackoverflow.com/questions/3974087/…
leebutts

31

Để biết danh sách thư mục, hãy thử

Dir['**/']

Danh sách tệp khó hơn, vì trong thư mục Unix cũng là tệp, vì vậy bạn cần kiểm tra loại hoặc loại bỏ các mục từ danh sách trả về là cha của các mục khác.

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

Và để có danh sách tất cả các tệp và thư mục, chỉ cần

Dir['**/*']

Lưu ý rằng anh ấy nói "cũng bao gồm các tệp", không phải "chỉ tệp" nên bạn không cần phải xóa các thư mục.
sepp2k

1
@ sepp2k Vâng, tôi đã bỏ lỡ phần này khi tôi đang chơi với irb. Nhưng tôi để điều này ở đây trong trường hợp ai đó có thể tìm kiếm thứ gì đó tương tự :-)
MBO

7

Nhanh một lớp lót

Chỉ các thư mục

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

Thư mục và tệp bình thường

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

Ruby đẹp tinh khiết

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

Bất cứ ai có thể giải thích end.select {}.flatten()một phần? Tôi thích chức năng tổng thể. Có vẻ như sẽ tạo ra một mảng mảng? Có thể thực hiện elseifphần với: rec_path(child, file) << child.to_sđể bạn có thể gán nó vào một mảng và nhận một mảng chuỗi không? Cảm ơn!
MCP

7

Như đã lưu ý trong các câu trả lời khác ở đây, bạn có thể sử dụng Dir.glob. Hãy nhớ rằng các thư mục có thể có nhiều ký tự lạ trong đó và đối số hình cầu là các mẫu, vì vậy một số ký tự có ý nghĩa đặc biệt. Do đó, sẽ không an toàn khi làm những điều như sau:

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

Thay vào đó hãy làm:

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

2

Trong PHP hoặc các ngôn ngữ khác để lấy nội dung của một thư mục và tất cả các thư mục con của nó, bạn phải viết một số dòng mã, nhưng trong Ruby thì phải mất 2 dòng:

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

điều này sẽ in nội dung của thư mục hiện tại và tất cả các thư mục con của nó.

Hoặc ngắn hơn, Bạn có thể sử dụng ’**’ký hiệu:

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

Bạn sẽ viết bao nhiêu dòng bằng PHP hoặc bằng Java để nhận được cùng một kết quả?


13
Downvoted cho trực tiếp copy-dán từ mustap.com/rubyzone_post_162_recursive-directory-listing mà không nêu rõ nguồn gốc ...
eckza

@kivetros Tôi đã chỉnh sửa câu trả lời để bao gồm phiên bản lưu trữ của liên kết :-)
onebree

0

Mặc dù không phải là giải pháp một dòng, nhưng tôi nghĩ đây là cách tốt nhất để thực hiện bằng cách gọi ruby.

Đầu tiên xóa tất cả các tệp một cách đệ quy
Thứ hai xóa tất cả các thư mục trống

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

3
Anh ấy / cô ấy không muốn xóa tệp / thư mục.
Darek Nędza

Làm cách nào để thực hiện việc này cho cả tệp + thư mục trong một dòng?
vipin8169

0

Dưới đây là một ví dụ kết hợp tính năng khám phá động của thư mục dự án Rails với Dir.glob:

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

Tôi cố gắng này >> config.assets.paths << Rails.root.join("app", "assets", "*"), nhưng vẫn không thể nhìn thấy các thư mục con và các tập tin bên trong thư mục tài sản doRails.application.config.assets.paths
vipin8169

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

dấu chấm trả về nil, sử dụng compact


1
Điều này không quá thanh lịch và sẽ cần phải nói thêm một vài dòng nữa để trở nên như vậy
một
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.