109

What is the fastest, most optimized, one-liner way to get an array of the directories (excluding files) in Ruby?

How about including files?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Lance
  • 75,200
  • 93
  • 289
  • 503
  • 3
    Fastest, most optimized and one-liner can be at odds with readable/maintainable. And, you could find this out using a benchmark and quick testing. – the Tin Man May 27 '16 at 19:34

9 Answers9

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

Instead of Dir.glob(foo) you can also write Dir[foo] (however Dir.glob can also take a block, in which case it will yield each path instead of creating an array).

Ruby Glob Docs

cameck
  • 2,058
  • 20
  • 32
sepp2k
  • 363,768
  • 54
  • 674
  • 675
54

I believe none of the solutions here deal with hidden directories (e.g. '.test'):

require 'find'
Find.find('.') { |e| puts e if File.directory?(e) }
FelipeC
  • 9,123
  • 4
  • 44
  • 38
35

For list of directories try

Dir['**/']

List of files is harder, because in Unix directory is also a file, so you need to test for type or remove entries from returned list which is parent of other entries.

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

And for list of all files and directories simply

Dir['**/*']
MBO
  • 30,379
  • 5
  • 50
  • 52
  • Note that he said "also include files", not "only files" so you don't need to remove the directories. – sepp2k Mar 03 '10 at 11:43
  • 3
    @sepp2k Yes, I missed this part when I was playing with irb. But I leave this here in case someone might search for something similar :-) – MBO Mar 03 '10 at 11:45
8

As noted in other answers here, you can use Dir.glob. Keep in mind that folders can have lots of strange characters in them, and glob arguments are patterns, so some characters have special meanings. As such, it's unsafe to do something like the following:

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

Instead do:

Dir.chdir(folder) { Dir.glob("**/*").map {|path| File.expand_path(path) } }
troelskn
  • 115,121
  • 27
  • 131
  • 155
7

Fast one liner

Only directories

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

Directories and normal files

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

Pure beautiful 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)
johannes
  • 7,262
  • 5
  • 38
  • 57
  • 1
    False: Dir.glob("#{DIRECTORY}/**/*/").map {|directory| Pathname.new(directory) } – Robert Ross Feb 12 '13 at 20:14
  • Can anyone explain the `end.select {}.flatten()` part? I like the function overall. It looks like that will create an array of arrays? Would it be possible to do the `elseif` part with: `rec_path(child, file) << child.to_s` so that you could assign it to an array and get an array of strings? Thanks! – MCP Jun 03 '13 at 05:30
2

In PHP or other languages to get the content of a directory and all its subdirectories, you have to write some lines of code, but in Ruby it takes 2 lines:

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

this will print the content of the current directory and all its subdirectories.

Or shorter, You can use the ’**’ notation :

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

How many lines will you write in PHP or in Java to get the same result?

cha0site
  • 10,517
  • 3
  • 33
  • 51
Ramesh
  • 277
  • 1
  • 12
  • 15
    Downvoted for directly copy-pasting from http://www.mustap.com/rubyzone_post_162_recursive-directory-listing without citing the source... – eckza Mar 29 '11 at 00:28
  • @kivetros I edited the answer to include the archived version of the link :-) – onebree Aug 13 '15 at 12:45
0

Here's an example that combines dynamic discovery of a Rails project directory with Dir.glob:

dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))
shacker
  • 14,712
  • 8
  • 89
  • 89
  • I tried this>> `config.assets.paths << Rails.root.join("app", "assets", "*")`, but still couldn't see the sub-folders and files inside the assets folder by `Rails.application.config.assets.paths` – Vipin Verma Mar 14 '16 at 08:52
-1
Dir.open(Dir.pwd).map { |h| (File.file?(h) ? "#{h} - file" : "#{h} - folder") if h[0] != '.' }

dots return nil, use compact

ruvan
  • 438
  • 5
  • 7
-3

Although not a one line solution, I think this is the best way to do it using ruby calls.

First delete all the files recursively
Second delete all the empty directories

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