#!/usr/bin/ruby # == Synopsis # # Output a report of where your hard disk space has gone, organized by folder # (subdirectory), with the most bloated folders at the top. # # == Usage # # bloat [ -h | --help ] [ [ -b | --binary ] | [ -d | --decimal ] ] dir # # dir:: # The starting directory. Disk space is summarized for all directories # below it. # # --binary reports bloat in base 2 units (MiB, GiB) # # --decimal reports bloat in base 10 units (MB, GB), the default because # that's how hard disks are measured [1] # # --files includes sizes for all files, not just directories # # [1] http://lpar.ath0.com/2008/07/15/si-unit-prefixes-a-plea-for-sanity/ # # == Author # mathew (mailto:meta@pobox.com) # # == Copyright # Copyright © 2005 mathew. Licensed under the same terms as Ruby. require 'getoptlong' require 'find' require 'rubygems' require 'rdoc' # Default @base for output @base = 10 @files = false # Return a number in appropriate units, nicely justified, as a string def formattednumber(x) u = 0 while (x > @divisor) x = x / @divisor u = u + 1 end return sprintf("%4d %-#{@width}s", x, @suffix[u]) end # Now the main program begins # Get arguments opts = GetoptLong.new( [ '--help', '-h', GetoptLong::NO_ARGUMENT ], [ '--binary', '-b', GetoptLong::NO_ARGUMENT ], [ '--decimal', '-d', GetoptLong::NO_ARGUMENT ], [ '--files', '-f', GetoptLong::NO_ARGUMENT ] ) # Parse them and act on them opts.each do |opt, arg| case opt when '--help' # used to do RDoc::usage, but that was removed from rdoc and I haven't # found a good replacement yet when '--binary' @base = 2 when '--decimal' @base = 10 when '--files' @files = true; else puts "Unrecognized option #{opt}" exit 0 end end # Now work out the unit suffixes and ratio between them if @base == 2 @suffix = ['B', 'KiB', 'MiB', 'GiB', 'TiB'] @divisor = 1024 @width = 3 else @suffix = ['B', 'kB', 'MB', 'GB', 'TB'] @divisor = 1000 @width = 2 end # Should be 1 remaining argument, the directory to start with if ARGV.length != 1 #RDoc::usage exit 0 end # Perform the find and total the bloat bloat = Hash.new Find.find(ARGV[0]) do |file| # Find.prune if file == '.' stat = File.lstat(file) dir = File.dirname(file) if stat.file? if bloat[dir] bloat[dir] += stat.size else bloat[dir] = stat.size end end if @files bloat[file] = stat.size end end # Sort by reverse bloatyness bloatarray = bloat.sort {|pair1, pair2| pair2[1] <=> pair1[1]} # Output for pair in bloatarray print formattednumber(pair[1]), ' ', pair[0], "\n" end