1

This is similar to What's the Ruby equivalent of Python's os.walk?, but I'm interested in walking the directory tree from the leaves back, rather than the root out.

I.e., for a directory structure like

/root/
|- A/
   |- a.txt
|- B/
   |- b.txt
   |- C/
      |- c.txt

Given root, I'd like to traverse it in the following order.

  1. /root/A/a.txt
  2. /root/A
  3. /root/B/C/c.txt
  4. /root/B/C
  5. /root/B/b.txt
  6. /root/B

I need to replace file content and rename both files and directories during the traversal, so variations on that order would be OK. Because of the directory renaming, starting at the root directory isn't an attractive option.

Community
  • 1
  • 1
ESV
  • 7,620
  • 4
  • 39
  • 29
  • Do you mean [like this](http://stackoverflow.com/questions/3498539/searching-a-folder-and-all-of-its-subfolders-for-files-of-a-certain-type)? – tadman May 06 '16 at 21:22
  • @tadman The accepted answer on that question points to the Find module, whose documentation says it “supports the top-down traversal of a set of file paths.” OP is asking for the opposite: Bottom-up traversal. – Jordan Running May 06 '16 at 21:33
  • 1
    It might work if you just reverse the list of what you find. Depends! There's a few options explored there. – tadman May 06 '16 at 21:45
  • 1
    https://github.com/samonzeweb/walk – Casper May 06 '16 at 21:45
  • Out of interest, what do you expect/want to happen if there was *also* a folder `/root/B/D` containing text files - are you expecting to start from C, then find the *sibling* directory? – Neil Slater May 06 '16 at 21:52
  • @NeilSlater, yes, siblings all the way down. I've added to the example directory hierarchy to clarify that. – ESV May 06 '16 at 21:57
  • @Casper, that looks promising. Any reason you didn't make it a full-fledged answer instead of a comment? – ESV May 06 '16 at 22:28
  • If it does what you need perhaps write it as an answer and accept? I'll upvoat. – Casper May 06 '16 at 22:51

1 Answers1

0

Although I originally wrote my own solution to this (included below), I like Casper's suggestion, http://github.com/samonzeweb/walk, better since it behaves exactly as os.walk(x, topdown=false) does in Python.

My original solution follows. It's usage differs from os.walk() because it yields individual file and directory paths, rather than a tuple of (path, subdirs, files).

def bottomup_path_walk(dir, &block)
  files = []
  subdirs = []
  Dir.glob(File.join(dir, "*")).each do |path_str|
    path = Pathname.new(path_str)
    if path.directory?
      bottomup_path_walk(path, &block)
      subdirs << path
    elsif path.file?
      files << path
    end
  end

  files.each   { |f| yield f }
  subdirs.each { |d| yield d }
end

Given the directory tree in the question, the preceding code traverses in this order (which is safe for renaming both files and directories).

  1. /root/B/C/c.txt
  2. /root/B/b.txt
  3. /root/B/C
  4. /root/B/b.txt
  5. /root/A/a.txt
  6. /root/A
  7. /root/B
Community
  • 1
  • 1
ESV
  • 7,620
  • 4
  • 39
  • 29