Getting a list of folders in a directory
Asked Answered
L

13

99

How do I get a list of the folders that exist in a certain directory with ruby?

Dir.entries() looks close but I don't know how to limit to folders only.

Labelle answered 14/12, 2009 at 5:26 Comment(0)
E
78

Jordan is close, but Dir.entries doesn't return the full path that File.directory? expects. Try this:

 Dir.entries('/your_dir').select {|entry| File.directory? File.join('/your_dir',entry) and !(entry =='.' || entry == '..') }
Enjoyable answered 14/12, 2009 at 6:2 Comment(4)
Note that this will get you all directories, including hidden ones as well as '.' (current directory) and '..' (parent of current directory). In most cases, you want to remove at least those two.Whippet
I prefer this one... Dir.entries(root).select { |entry| File.directory? File.join(root, entry) and not entry.in? %w[. ..]}Erythro
But I summited a solution much more clear and succinct, using the Dir.glob.Erythro
This is just objectively worse than Dir.glob() as seen in the other answer -- I'd strongly recommend just doing that instead of thisRonnieronny
A
119

I've found this more useful and easy to use:

Dir.chdir('/destination_directory')
Dir.glob('*').select {|f| File.directory? f}

it gets all folders in the current directory, excluded . and ...

To recurse folders simply use ** in place of *.

The Dir.glob line can also be passed to Dir.chdir as a block:

Dir.chdir('/destination directory') do
  Dir.glob('*').select { |f| File.directory? f }
end
Acropetal answered 30/5, 2011 at 20:20 Comment(3)
To recurse folders, you need to use **/* in place of *.Sophiasophie
Simple and best. Thank youChaiken
Excellent answer.Pint
E
78

Jordan is close, but Dir.entries doesn't return the full path that File.directory? expects. Try this:

 Dir.entries('/your_dir').select {|entry| File.directory? File.join('/your_dir',entry) and !(entry =='.' || entry == '..') }
Enjoyable answered 14/12, 2009 at 6:2 Comment(4)
Note that this will get you all directories, including hidden ones as well as '.' (current directory) and '..' (parent of current directory). In most cases, you want to remove at least those two.Whippet
I prefer this one... Dir.entries(root).select { |entry| File.directory? File.join(root, entry) and not entry.in? %w[. ..]}Erythro
But I summited a solution much more clear and succinct, using the Dir.glob.Erythro
This is just objectively worse than Dir.glob() as seen in the other answer -- I'd strongly recommend just doing that instead of thisRonnieronny
A
50

In my opinion Pathname is much better suited for filenames than plain strings.

require "pathname"
Pathname.new(directory_name).children.select { |c| c.directory? }

This gives you an array of all directories in that directory as Pathname objects.

If you want to have strings

Pathname.new(directory_name).children.select { |c| c.directory? }.collect { |p| p.to_s }

If directory_name was absolute, these strings are absolute too.

Alow answered 14/12, 2009 at 9:27 Comment(2)
another reason for using Pathname is that it automatically removes ., .. and proprietery files like .DS_StoreCappella
more tersely: Pathname.new(somepath).children.select(&:directory?)Euthanasia
F
20

Recursively find all folders under a certain directory:

Dir.glob 'certain_directory/**/*/'

Non-recursively version:

Dir.glob 'certain_directory/*/'

Note: Dir.[] works like Dir.glob.

Fro answered 18/3, 2013 at 9:9 Comment(1)
How would you do recursive and non-recursive file find using same logic? And how recursive and non-recursive file and folders?Bedsore
E
6

With this one, you can get the array of a full path to your directories, subdirectories, subsubdirectories in a recursive way. I used that code to eager load these files inside config/application file.

Dir.glob("path/to/your/dir/**/*").select { |entry| File.directory? entry }

In addition we don't need deal with the boring . and .. anymore. The accepted answer needed to deal with them.

Erythro answered 6/6, 2019 at 1:37 Comment(0)
C
4

You can use File.directory? from the FileTest module to find out if a file is a directory. Combining this with Dir.entries makes for a nice one(ish)-liner:

directory = 'some_dir'
Dir.entries(directory).select { |file| File.directory?(File.join(directory, file)) }

Edit: Updated per ScottD's correction.

Chicanery answered 14/12, 2009 at 5:34 Comment(0)
O
4
directory = 'Folder'
puts Dir.entries(directory).select { |file| File.directory? File.join(directory, file)}
Ornithine answered 14/12, 2009 at 9:5 Comment(0)
A
2
$dir_target = "/Users/david/Movies/Camtasia 2/AzureMobileServices.cmproj/media"

Dir.glob("#{$dir_target}/**/*").each do |f| 
  if File.directory?(f)
    puts "#{f}\n"
  end
end
Anticlockwise answered 15/5, 2014 at 10:0 Comment(0)
S
1
Dir.glob('/your_dir').reject {|e| !File.directory?(e)}
Sedimentology answered 26/8, 2013 at 18:16 Comment(1)
Or, instead of reject !, selectCharger
C
1

For a generic solution you probably want to use

Dir.glob(File.expand_path(path))

This will work with paths like ~/*/ (all folders within your home directory).

Cherian answered 25/8, 2017 at 15:12 Comment(1)
Thanks! This is very helpful.Pint
T
1

We can combine Borh's answer and johannes' answer to get quite an elegant solution to getting the directory names in a folder.

# user globbing to get a list of directories for a path
base_dir_path = ''
directory_paths = Dir.glob(File.join(base_dir_path, '*', ''))

# or recursive version:
directory_paths = Dir.glob(File.join(base_dir_path, '**', '*', ''))

# cast to Pathname
directories = directory_paths.collect {|path| Pathname.new(path) }

# return the basename of the directories
directory_names = directories.collect {|dir| dir.basename.to_s }
Tyus answered 7/12, 2017 at 3:26 Comment(0)
H
1

Only folders ('.' and '..' are excluded):

Dir.glob(File.join(path, "*", File::SEPARATOR))

Folders and files:

Dir.glob(File.join(path, "*"))

Hydromancy answered 26/1, 2018 at 11:17 Comment(0)
G
0

I think you can test each file to see if it is a directory with FileTest.directory? (file_name). See the documentation for FileTest for more info.

Genesisgenet answered 14/12, 2009 at 5:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.