在Ruby中递归列出目录的一行代码是什么?

110

在Ruby中,最快、最优化的一行代码获取目录数组(排除文件)的方式是什么?

如果要包括文件呢?


3
最快、最优化和一行代码可能与可读性/可维护性相矛盾。可以通过基准测试和快速测试发现这一点。 - the Tin Man
9个回答

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

你可以用 Dir[foo] 代替 Dir.glob(foo),但是如果你想使用 Dir.glob 的块形式,它会遍历每个路径而不是创建一个数组。

Ruby Glob Docs


10
除非你也想要符号链接,否则请使用Dir.glob("**/") - johannes
6
隐藏文件和目录怎么办? - alediaferia
6
要在匹配结果中包含点文件,请使用File::FNM_DOTMATCH标志。 - x-yuri
2
感谢@x-yuri!顺便说一下,标志是这样指定的:Dir.glob("**/*", File::FNM_DOTMATCH) - vlz
2
这是文档:http://www.ruby-doc.org/core-2.2.0/Dir.html#method-c-glob - stephen.hanson
Dir::glob 的一个重要考虑因素是,如果您的路径包含 \?.[]{} 中的任何字符,则必须对其进行转义。 - taylorthurlow

54

我认为这里的解决方案都没有处理隐藏目录(例如'.test'):

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

Find.find('/tmp').collect {|_|_} 对我很有帮助。 - Alexander Bird
小心使用Find命令,它不会遵循符号链接:https://dev59.com/UG865IYBdhLWcg3wHK7u - leebutts

36

获取目录列表可尝试使用以下方法:

Dir['**/']

列出文件列表更加困难,因为在Unix系统中目录也是一种文件类型,所以你需要测试每个条目的类型或者从返回的列表中删除那些包含其他条目的父级目录。

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

要列出所有文件和目录,只需执行以下操作:

Dir['**/*']

请注意他说的是“还包括文件”,而不是“仅限文件”,因此您无需删除目录。 - sepp2k
3
@sepp2k 是的,当我在使用 irb 时,我错过了这个部分。但我还是把它留在这里,以防有人搜索类似的内容 :-) - MBO

8

如其他答案所述,您可以使用Dir.glob。请记住,文件夹中可能会有很多奇怪的字符,并且glob参数是模式,因此某些字符具有特殊含义。因此,像下面这样做是不安全的:

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

改为如下实现:

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

7

快速一行代码

仅限目录

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

目录和普通文件

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

纯美的Ruby

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
Dir.glob("#{DIRECTORY}/**/*/").map {|directory| Pathname.new(directory) } 假:False - Robert Ross
有人能解释一下 end.select {}.flatten() 这部分吗?我喜欢这个函数的整体效果。看起来它会创建一个数组的数组?是否可能使用 rec_path(child, file) << child.to_s 来完成 elseif 部分,以便您可以将其分配给一个数组并获得一个字符串数组?谢谢! - MCP

2

在PHP或其他语言中,要获取目录及其所有子目录的内容,您需要编写几行代码,但在Ruby中只需要两行:

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

这将打印当前目录及其所有子目录的内容。

或者更简洁地说,您可以使用'**'符号:

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

你需要写多少行PHP或Java代码才能得到相同的结果?


15
因为没有引用来源,直接从http://www.mustap.com/rubyzone_post_162_recursive-directory-listing复制粘贴被downvote了... - eckza
@kivetros 我编辑了答案,包括链接的存档版本 :-) - onebree

0
这是一个结合了Rails项目目录的动态发现和Dir.glob的示例:
dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))

我尝试了这个>> config.assets.paths << Rails.root.join("app", "assets", "*"),但是仍然无法通过Rails.application.config.assets.paths看到资产文件夹内的子文件夹和文件。 - Vipin Verma

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

点返回nil,使用压缩


1
这不太优雅,需要再多写几行才行。 - onebree

-3

虽然不是一行代码的解决方案,但我认为这是使用 Ruby 调用的最佳方法。

首先递归删除所有文件
其次删除所有空目录

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

4
他/她不想删除文件/目录。 - Darek Nędza
如何在一行代码中同时处理文件和目录? - Vipin Verma
1
哇,这是一个非常糟糕的答案:a.) 它没有回答原来的问题,b.) 当被不熟练的人复制和粘贴时,它是具有破坏性的... - lumpidu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接