#!/bin/bash # tree2.sh # Lightly modified/reformatted by ABS Guide author. # Included in ABS Guide with permission of script author (thanks!). ## Recursive file/dirsize checking script, by Patsie ## ## This script builds a list of files/directories and their size (du -akx) ## and processes this list to a human readable tree shape ## The 'du -akx' is only as good as the permissions the owner has. ## So preferably run as root* to get the best results, or use only on ## directories for which you have read permissions. Anything you can't ## read is not in the list. #* ABS Guide author advises caution when running scripts as root! ########## THIS IS CONFIGURABLE ########## TOP=5 # Top 5 biggest (sub)directories. MAXRECURS=5 # Max 5 subdirectories/recursions deep. E_BL=80 # Blank line already returned. E_DIR=81 # Directory not specified. ########## DON'T CHANGE ANYTHING BELOW THIS LINE ########## PID=$$ # Our own process ID. SELF=`basename $0` # Our own program name. TMP="/tmp/${SELF}.${PID}.tmp" # Temporary 'du' result. # Convert number to dotted thousand. function dot { echo " $*" | sed -e :a -e 's/\(.*[0-9]\)\([0-9]\{3\}\)/\1,\2/;ta' | tail -c 12; } # Usage: tree function tree { recurs="$1" # How deep nested are we? prefix="$2" # What do we display before file/dirname? minsize="$3" # What is the minumum file/dirsize? dirname="$4" # Which directory are we checking? # Get ($TOP) biggest subdirs/subfiles from TMP file. LIST=`egrep "[[:space:]]${dirname}/[^/]*$" "$TMP" | awk '{if($1>'$minsize') print;}' | sort -nr | head -$TOP` [ -z "$LIST" ] && return # Empty list, then go back. cnt=0 num=`echo "$LIST" | wc -l` # How many entries in the list. ## Main loop echo "$LIST" | while read size name; do ((cnt+=1)) # Count entry number. bname=`basename "$name"` # We only need a basename of the entry. [ -d "$name" ] && bname="$bname/" # If it's a directory, append a slash. echo "`dot $size`$prefix +-$bname" # Display the result. # Call ourself recursively if it's a directory #+ and we're not nested too deep ($MAXRECURS). # The recursion goes up: $((recurs+1)) # The prefix gets a space if it's the last entry, #+ or a pipe if there are more entries. # The minimum file/dirsize becomes #+ a tenth of his parent: $((size/10)). # Last argument is the full directory name to check. if [ -d "$name" -a $recurs -lt $MAXRECURS ]; then [ $cnt -lt $num ] \ || (tree $((recurs+1)) "$prefix " $((size/10)) "$name") \ && (tree $((recurs+1)) "$prefix |" $((size/10)) "$name") fi done [ $? -eq 0 ] && echo " $prefix" # Every time we jump back add a 'blank' line. return $E_BL # We return 80 to tell we added a blank line already. } ### ### ### main program ### ### ### rootdir="$@" [ -d "$rootdir" ] || { echo "$SELF: Usage: $SELF " >&2; exit $E_DIR; } # We should be called with a directory name. echo "Building inventory list, please wait ..." # Show "please wait" message. du -akx "$rootdir" 1>"$TMP" 2>/dev/null # Build a temporary list of all files/dirs and their size. size=`tail -1 "$TMP" | awk '{print $1}'` # What is our rootdirectory's size? echo "`dot $size` $rootdir" # Display rootdirectory's entry. tree 0 "" 0 "$rootdir" # Display the tree below our rootdirectory. rm "$TMP" 2>/dev/null # Clean up TMP file. exit $?