6

i need a recursive function to list files in a folder:

def procdir(dirname)
  data = ''
  Dir.foreach(dirname) do |dir|
    dirpath = dirname + '/' + dir
    if File.directory?(dirpath) then
      if dir != '.' && dir != '..' then
        #puts "DIRECTORY: #{dirpath}" ; 
        procdir(dirpath)
      end
    else
      data += dirpath
    end
  end
  return data
end

but the result: is null

Morgan
  • 19,934
  • 8
  • 58
  • 84
indi
  • 125
  • 1
  • 3
  • 5
  • Could you tell me the filesystem? Does `dirname` contains multiple directories itself within it? – Arup Rakshit Mar 19 '13 at 15:06
  • 1
    possible duplicate of [One-liner to Recursively List Directories in Ruby?](http://stackoverflow.com/questions/2370702/one-liner-to-recursively-list-directories-in-ruby) – dbenhur Mar 19 '13 at 15:14

5 Answers5

21

Stdlib Dir#glob recurses when you give it the ** glob.

def procdir(dir)
  Dir[ File.join(dir, '**', '*') ].reject { |p| File.directory? p }
end
dbenhur
  • 20,008
  • 4
  • 48
  • 45
  • 1
    Thank for your responses, i understand my problem. dbenhur, your code is great! here is my code if it can help someone def procdir(dir) Dir[ File.join(dir, '**', '*') ].reject { |p| File.directory? p } end file = procdir('mypath') #puts file file.each do |filename| #puts filename test = filename.scan(/SomeRegex/).flatten puts test (..) end Thank you all – indi Mar 19 '13 at 15:16
  • Nice this is exactly what I was looking for – GoldenWest Jan 24 '20 at 22:44
8

Use the find module:

require 'find'

pathes = []
Find.find('.') do |path|
  pathes << path unless FileTest.directory?(path)
end

puts pathes.inspect
ckruse
  • 9,642
  • 1
  • 25
  • 25
7

Old thread but perhaps someone might find it useful:

array_of_all_files = Dir .glob("**/*") .reject { |file_path| File.directory? file_path }

Jikku Jose
  • 18,306
  • 11
  • 41
  • 61
  • 3
    Why did you repeat an answer nearly identical to the one I [posted eight months earlier](http://stackoverflow.com/a/15503079/1074296)? [`Dir::[]`](http://ruby-doc.org/core-2.0/Dir.html#method-c-5B-5D) is the same as `Dir.glob`. `File.join('**', '*')` is a more portable way to say `"**/*"`. – dbenhur Dec 27 '13 at 05:55
  • I am sorry, I didn't know they were identical. And I felt this was more readable (probably, since I used it a bunch of times and never knew another representation of it). – Jikku Jose Dec 27 '13 at 11:49
  • @dbenhur : Just curious, why would `File.join('**', '*')` be more portable than `"**/*"`. It works on Linux/Windows/MacOs as far as I know. – Eric Duminil Mar 02 '17 at 12:02
  • @EricDuminil Because there are more operating systems than that. [`File::join`](https://ruby-doc.org/core-2.2.0/File.html#method-c-join) will join on `File::SEPARATOR` and not assume the underlying OS understands `/`. – dbenhur Mar 10 '17 at 05:42
  • @dbenhur do you have any concrete example where `/` wouldn't work? – Eric Duminil Mar 10 '17 at 07:17
  • @EricDuminil In the context of `Dir.glob`, slash will always work because the ruby lib is doing the actual globbing. It's a bad habit to get into though if you want your ruby to be broadly portable. In DOSish systems (Windows), the OS calls usually understand either \ or / but not every program does, so you may construct file paths which will not be understood in that system. Basically, any non-POSIX OS may give you trouble if you assume `File::SEPARATOR == '/'` – dbenhur Apr 03 '17 at 22:03
  • 1
    @dbenhur: I agree that it can be a problem when using those paths with other programs. But `File.join` doesn't change anything : `File.join("a","b")` is `"a/b"`, even on Windows. – Eric Duminil Apr 04 '17 at 08:04
1

It looks like there are a couple of problems with the recursion:

  • The else clause appears to associated with the wrong if. It needs to be associated with the first if.
  • The result of the recursive procdir call should be added to data.

If you indent the code a little more cleanly, it would probably be easier to spot problems like that. The following contains the two fixes:

def procdir(dirname)
  data = ''
  Dir.foreach(dirname) do |dir|
    dirpath = dirname + '/' + dir
    if File.directory?(dirpath) then
      if dir != '.' && dir != '..' then
        #puts "DIRECTORY: #{dirpath}" ; 
        data += procdir(dirpath)
      end
    else
      data += dirpath
    end
  end
  return data
end
Mark Wilkins
  • 40,729
  • 5
  • 57
  • 110
0

If you know the file extensions you will have just use this:

Dir[Rails.root.join('config/locales/**/*.{rb,yml}')]

Bruno Casali
  • 1,339
  • 2
  • 17
  • 32