#!/bin/sh # # SccsId[] = "@(#)biggest.sh 1.9 05/22/07 (List 'biggest' files in filesystem)" # #----------------------------------------------------------------------# # biggest.sh # # -------------------------------------------------------------------- # # # # Copyright (c) 1995-2007 by Bob Orlando. All rights reserved. # # # # Permission to use, copy, modify and distribute this software # # and its documentation for any purpose and without fee is hereby # # granted, provided that the above copyright notice appear in all # # copies, and that both the copyright notice and this permission # # notice appear in supporting documentation, and that the name of # # Bob Orlando not be used in advertising or publicity pertaining # # to distribution of the software without specific, written prior # # permission. Bob Orlando makes no representations about the # # suitability of this software for any purpose. It is provided # # "as is" without express or implied warranty. # # # # BOB ORLANDO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS # # SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY # # AND FITNESS. IN NO EVENT SHALL BOB ORLANDO BE LIABLE FOR ANY # # SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER # # IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, # # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF # # THIS SOFTWARE. # # # # -------------------------------------------------------------------- # # Program documentation and notes located at the bottom. # #----------------------------------------------------------------------# #----------------------------------------------------------------# # Script_name assignment is necessary if there exists the # # possibility that this process may be run by the 'at' command. # # Run via 'at' and $0 simply returns '/bin/sh' or 'sh' (hardly # # desirable if you run that into basename). # #----------------------------------------------------------------# script_name="biggest.sh" [ $0 = "/bin/sh" -o `dirname $0` = "." ] \ && script_home=`pwd` || script_home=`dirname $0` bin=/usr/bin # Default moi=`expr "\`id\`" : 'uid=[0-9]*(\(.*\)) .*'` #----------------------------------------------------------------# # Do our best to find and assign $AWK executable variable. # #----------------------------------------------------------------# { [ -x /usr/bin/nawk ] && AWK=/usr/bin/nawk ; } \ || { [ -x /bin/nawk ] && AWK=/bin/nawk ; } \ || { [ -x /usr/bin/gawk ] && AWK=/usr/bin/gawk ; } \ || { [ -x /bin/gawk ] && AWK=/bin/gawk ; } \ || { [ -x /usr/gnu/bin/gawk ] && AWK=/usr/gnu/bin/gawk ; } \ || { [ -x /usr/bin/awk ] && AWK=/usr/bin/awk ; } \ || { [ -x /bin/awk ] && AWK=/bin/awk ; } #======================================================================# # L O C A L F U N C T I O N S # # (in alphabetical order) # #----------------------------------------------------------------------# EXIT_USAGE() #----------------------------------------------------------------------# { echo "Usage: biggest.sh -fHh -l -s -t -v fs\n" 1>&2 echo " -f = follow links" 1>&2 echo " -H = Full documentation" 1>&2 echo " -h = Usage brief" 1>&2 echo " -l = Displays lines" 1>&2 echo " -s = Minimum file size is " 1>&2 echo " -t = Temp/work directory, " 1>&2 echo " -v = Edit (vi) file list" 1>&2 echo " fs = Required filesystem argument." 1>&2 echo "" 1>&2 exit 1 } #----------------------------------------------------------------------# SHOW_DOCUMENTATION() # Function documentation located at bottom. # #----------------------------------------------------------------------# { #----------------------------------------------------------------# # If the following variables are not set, use these as defaults. # #----------------------------------------------------------------# : ${script_name:=`basename $0`} : ${script_home:=`dirname $0`} SD_script_home=`echo $script_home | sed 's/\/*$/\//'` #------------------------------------------------# # User wants help, so find the documentation # # section and print everything from there down. # #------------------------------------------------# $AWK -v script_name=$script_name \ 'BEGIN { n=0 } { #------------------------------------------# # Until we find the documentation section, # # keep looking at each line. # #------------------------------------------# if (n == 0) { if ($0 ~ /^# +D O C U M E N T A T I O N/) { n = NR print line print $0 } else { line = $0 } next } #-------------------------------------# else # Once we find it, print until EOF. # { #-------------------------------------# print } } END { if (n == 0) # Means there is no documentation section. { "date +%Y-%m-%d" | getline yyyy_mm_dd print yyyy_mm_dd" NO DOCUMENTATION", "section found for "script_name".\a" | "cat 1>&2" exit 1 # Exit failure } exit 0 # Else exit success }' ${SD_script_home}$script_name exit $? } # "SD_" prefix identifies this function's variables #======================================================================# # I N I T I A L I Z A T I O N # #======================================================================# opt_v=0 # Default 'vi' option (0 = Do NOT vi the file list) tmp=/var/tmp follow="" size="499999" # Default minimum filesize lines="500" # Default maximum lines while getopts fHhl:s:t:v opt 2> /dev/null do case "$opt" in f ) follow='-follow' ;; H ) SHOW_DOCUMENTATION;; h ) EXIT_USAGE ;; l ) lines="$OPTARG" ;; # Max number of lines to display. s ) size="$OPTARG" ;; # Minimum file size. t ) tmp="$OPTARG" ;; # Temp directory (if /var/tmp full) v ) opt_v=1 ;; * ) echo "Ignoring invalid option, $1.";; esac done #----------------------------------# # Shift past options to arguments. # #----------------------------------# shift `expr $OPTIND - 1` #======================================================================# # M A I N # #======================================================================# [ $# -eq 0 ] && EXIT_USAGE #-----------------------------------------------------------------# # Ensure we have write-access to temp/work directory. # #-----------------------------------------------------------------# if [ ! -d $tmp ]; then echo "Temp/work directory, $tmp not found!" \ "\n$script_name terminated." exit 1 elif [ ! -w $tmp ]; then echo "No write access to temp/work directory, $tmp!" \ "\n$script_name terminated." exit 1 fi #----------------------------------------------------------------# # File lists of remote filesystems is problematic, so we limit # # our operations to local filesystems only. # #----------------------------------------------------------------# df -lk $1 if [ $? -ne 0 ]; then echo "$1 MUST be a local filesystem--it is not!" \ "\n$script_name terminated." exit 1 fi #----------------------------------------------------------------# # Build a 'find' command with the necessary options/arguments. # # Be sure to exclude anything with cdrom in it and include -xdev # # -xdev if the filesystem being searched is root (/). # #----------------------------------------------------------------# outfile=$tmp/$moi"_biggest.files" # Formatted 'find' output include='-size +'"$size"'c -exec ls -lc {} \;' exclude='-o -fstype nfs -prune -o -name cdrom\* -prune' [ ."$1" = ."/" ] && find_opt="-xdev $follow" || find_opt="$follow" date "+%D %T" find_cmd="find $1 $find_opt $include $exclude -print" #----------------------------------------------------------------# # Display find command before running it. Use [gn]awk to format # # the output and sort it in descending order (biggest on top). # #----------------------------------------------------------------# echo "$find_cmd 2> /dev/null | $AWK" eval $find_cmd 2> /dev/null | $AWK \ 'BEGIN \ { i = 0 own = 3 siz = 5 mmm = 6 day = 7 yyy = 8 # This may actually be yyyy or hh:mi Mon = "^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$" } # "! /^[bcd]/" skips block and character devices and directories ! /^[bcd]/ \ { #-----------------------------------------------------------# # If it looks like owner and group fields are concatonated, # # try backing up the field ($n) list and work with that. # #-----------------------------------------------------------# if ($siz !~ /[0-9]+/ && !match($mmm,Mon)) { if ($(siz-1) ~ /[0-9]+/ && match($(mmm-1),Mon)) { siz = 4 # 4th field mmm = 5 # Etc. day = 6 yyy = 7 } } gsub(/[\t ]+/," ") # Squeeze whitespace. gsub(/./,"& ",$siz) # Isolate each digit, q=split($siz,a," ") # then split the $siz into an array. $siz="" # Clear $siz. for (p=1;q>0;q--) # Insert commas into $siz. { $siz=a[q]""$siz if ((p%3) == 0 && q != 1) $siz=","$siz # Insert commas here p++ } printf("%17s %-8s %s %02d %-5s %s\n", $siz, $own, $mmm, $day, $yyy, $NF) #-----------------------------------------------# # if size value is not 5, then reset it, et al. # #-----------------------------------------------# if (siz != 5) { siz = 5 mmm = 6 day = 7 yyy = 8 } }' | sort -r -k 1,2 | head -$lines > $outfile #----------------------------------------------------------------# # Unless 'vi' option was given, simply cat our file list. # #----------------------------------------------------------------# if [ `wc -l < $outfile` -eq 0 ]; then echo "No files found in $1 > $size bytes in size." else [ $opt_v -eq 0 ] && cat $outfile || vi $outfile fi exit $? #======================================================================# # D O C U M E N T A T I O N # #======================================================================# # # # Author: Bob Orlando (Bob@OrlandoKuntao.com) # # # # Date: April 8, 1995 # # # # Program ID: biggest.sh # # # # Code Contrl: aphrodite:~dmc/SCCS. # # # # Usage: biggest.sh -fHh -l -v -t -s fs # # # # -f = Follow links # # -H = Displays detailed documentation # # -h = Provides usage brief # # -l = Displays lines (default is 500) # # -s = Minimum file size is # # (default is 500K) # # -t = Use as temp/work directory # # (default is /var/tmp) # # -v = Edit (vi) file list # # fs = Required filesystem argument. # # # # Purpose: List biggest files in a given filesystem (files # # appear in descending order). # # # # Description: Using the find command, descend through the specified # # file system (fs) listing all files whose sizes exceed # # either the default minimum size (500K) or the minimum # # value provided via size (-s) option. The filelist # # is created in /var/tmp by default as it usually much # # larger than /tmp. However, in the event that /var # # is the filesystem that's full (or is not writable to # # the user), the temp dir (-t) option is available to # # redirect the output elsewhere. # # # # When root is the directory being searched, -xdev is # # supplied as a find argument so only root, and none # # of its subdirectories, is searched. # # # # With the 'vi' option (-v) the user can edit the # # normally cat'd file list. # # # # Modified: 2007-05-22 Bob Orlando # # v1.9 * Change $LOGNAME to $moi to reduce issues # # that can pop up when the user runs the # # script su'd as root one time, then run # # as the general user the next. # # # # 2005-09-26 Bob Orlando # # v1.8 * Change size field length in ... # # printf("%13s %-8s %s %02d %-5s %s\n", ... # # to # # printf("%17s %-8s %s %02d %-5s %s\n", ... # # allowing the program to list files > 9G. # # # #----------------------------------------------------------------------#