Ruby: how do I recursively find and remove empty d

2020-06-16 02:26发布

I'm trying to write some ruby that would recursively search a given directory for all empty child directories and remove them.

Thoughts?

Note: I'd like a script version if possible. This is both a practical need and a something to help me learn.

标签: ruby file
9条回答
干净又极端
2楼-- · 2020-06-16 02:40

I've tested this script on OS X, but if you are on Windows, you'll need to make changes.

You can find the files in a directory, including hidden files, with Dir#entries.

This code will delete directories which become empty once you've deleted any sub-directories.

def entries(dir)
  Dir.entries(dir) - [".", ".."]
end

def recursively_delete_empty(dir)
  subdirs = entries(dir).map { |f| File.join(dir, f) }.select { |f| File.directory? f }
  subdirs.each do |subdir|
    recursively_delete_empty subdir
  end

  if entries(dir).empty?
    puts "deleting #{dir}"
    Dir.rmdir dir
  end
end
查看更多
祖国的老花朵
3楼-- · 2020-06-16 02:47

For a pure shell solution, I found this very useful

  find "$dir" -depth -type d |
    while read sub; do
      [ "`cd "$sub"; echo .* * ?`" = ". .. * ?" ] || continue
      echo rmdir "$sub"
      #rmdir "$sub"
    done

But if you have gnu-find installed (not universal yet)...

  find . -depth -type d -empty -printf "rmdir %p\n"

this uses find with xargs...

  find . -depth -type d -print0 |
    xargs -0n1 sh -c '[ "`cd "$0"; echo .* * ?`" = ". .. * ?" ] &&
                        echo "rmdir $0";'
查看更多
三岁会撩人
4楼-- · 2020-06-16 02:51

Why not just use shell?

find . -type d -empty -exec rmdir '{}' \;

Does exactly what you want.

查看更多
够拽才男人
5楼-- · 2020-06-16 02:51
Dir.glob('**/*').each do |dir|
  begin
    Dir.rmdir dir if File.directory?(dir)
  # rescue # this can be dangereous unless used cautiously
  rescue Errno::ENOTEMPTY
  end
end
查看更多
放荡不羁爱自由
6楼-- · 2020-06-16 02:52
module MyExtensions
  module FileUtils
    # Gracefully delete dirs that are empty (or contain empty children).
    def rmdir_empty(*dirs)
      dirs.each do |dir|
        begin
          ndel = Dir.glob("#{dir}/**/", File::FNM_DOTMATCH).count do |d|
            begin; Dir.rmdir d; rescue SystemCallError; end
          end
        end while ndel > 0
      end
    end
  end

  module ::FileUtils
    extend FileUtils
  end
end
查看更多
爷的心禁止访问
7楼-- · 2020-06-16 02:54

You have to delete in reverse order, otherwise if you have an empty directory foo with a subdirectory bar you will delete bar, but not foo.

  Dir.glob(dir + "/**/*").select { |d| 
    File.directory?(d)
  }.reverse_each { |d| 
    if ((Dir.entries(d) - %w[ . .. ]).empty?)
      Dir.rmdir(d)
    end
  }
查看更多
登录 后发表回答