Ruby:我如何递归查找和删除空目录?

时间:2009-08-17 21:49:45

标签: ruby file

我正在尝试编写一些ruby,它会递归搜索给定目录中的所有空子目录并删除它们。

思想?

注意:如果可能的话,我想要一个脚本版本。这既是实际需要,也是帮助我学习的东西。

9 个答案:

答案 0 :(得分:16)

在红宝石中:

Dir['**/*']                                            \
  .select { |d| File.directory? d }                    \
  .select { |d| (Dir.entries(d) - %w[ . .. ]).empty? } \
  .each   { |d| Dir.rmdir d }

答案 1 :(得分:7)

查看kch,dB的例子。和上面的Vishnu一起,我认为这是一个更优雅的解决方案:

Dir['**/'].reverse_each { |d| Dir.rmdir d if Dir.entries(d).size == 2 }

我使用'**/'而不是'/**/*'作为glob,它只返回目录,因此我不必测试它是否是以后的目录。根据{{​​3}},我使用reverse_each代替sort.reverse.each,因为它更短,据说效率更高。我更喜欢Dir.entries(d).size == 2(Dir.entries(d) - %w[ . .. ]).empty?,因为它更容易阅读和理解,但如果您必须在Windows上运行脚本,(Dir.entries(d) - %w[ . .. ]).empty?可能会更好。

我在Mac OS X上对此进行了相当多的测试,即使使用递归的空目录也能正常运行。

答案 2 :(得分:3)

你必须以相反的顺序删除,否则如果你有一个带有子目录栏的空目录foo,你将删除bar,但不会删除foo。

  Dir.glob(dir + "/**/*").select { |d| 
    File.directory?(d)
  }.reverse_each { |d| 
    if ((Dir.entries(d) - %w[ . .. ]).empty?)
      Dir.rmdir(d)
    end
  }

答案 3 :(得分:2)

为什么不使用shell?

  找到。 -type d -empty -exec rmdir'{}'\;

完全符合你的要求。

答案 4 :(得分:2)

Dir['/Users/path/Movies/incompleteAnime/foom/**/*']. \
select { |d| File.directory? d }. \
sort.reverse. \
each {|d| Dir.rmdir(d) if Dir.entries(d).size ==  2}

就像第一个例子,但第一个例子似乎没有处理递归位。排序和反向确保我们首先处理最嵌套的目录。

我认为sort.reverse可以写成sort {|a,b| b <=> a}以提高效率

答案 5 :(得分:1)

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

我在OS X上测试了这个脚本,但是如果你在Windows上,则需要进行更改。

您可以使用Dir#entries找到目录中的文件,包括隐藏文件。

此代码将删除删除任何子目录后变为空的目录。

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

答案 8 :(得分:0)

对于纯壳解决方案,我发现这非常有用

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

但是如果您已经安装了gnu-find(还不是通用的)...

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

这与xargs一起使用find ...

  find . -depth -type d -print0 |
    xargs -0n1 sh -c '[ "`cd "$0"; echo .* * ?`" = ". .. * ?" ] &&
                        echo "rmdir $0";'