#!/bin/sh
exec `which perl` -x. $0 $*
#!/usr/bin/perl -w
#
# @(#)dispus 2.6 08/30/04
#
# dispus - Browse a directory tree to find out where all the space went.
#
# Written by Annihilannic (annihilannic@hotmail.com)
#
# Todo:
#
# o Parse all automount map files. Start with auto_master and
# auto.master, add any further maps to the array we're looping
# through as they are found. No longer needs to be OS senstive
# as we can just search for all and ignore any missing ones.
# o Won't work with NIS though; could always process them too...
# o http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/cmds/aixcmds1/automount.htm
#
# Bugs:
#
# o If a filesystem is automounted while running it will not be
# recognised as a separate filesystem, but mounts aren't checked
# regularly for efficacity.
# o Does not check secondary automounter configuration files, such
# as those used by a /- entry in the master file.
# o If 'mount' is not in the path issues a warning (due to perl
# -w switch) but does not 'die' gracefully.
# o Not recognising mount points in MacOS X.
# o Shebang line not working in Irix 6.5.20.
#
# Version history:
#
# 2.6 o Much better handling of shell metacharacters in file names.
# Thanks to Shawn Porter for suggestion and testing.
# o HP-UX and DEC OSF/1 changes and handling of HP-UX 'bdf'
# command. Thanks to Navin Jain for code.
#
# 2.5 o Hard coded ignored mount point /tmp_mnt on AIX.
# o Changes for MacOS X compatibility.
# o Fixed bug reading stty output on cygwin/Linux.
# o Removed directory reference in 'ls' command to allow it to
# work in a directory containing many files. Works fine until
# ls output exceeds ~32768 bytes.
#
# 2.4 o Changed the prompt to match the new name (Oops).
# o Some changes for AIX compatibility. Thanks to Lloyd Blauen
# for testing.
#
# 2.3 o Moved 'commas' code into a subroutine and used it to display
# 'df' totals as well.
# o Added 'x' option to quit at Ed Schaefer's request.
# o Slightly changed 'df' output processing to recognise devices
# that don't begin with '/'.
#
# 2.2 o Renamed from 'dusage.pl' to 'dispus', a contraction of DIsk
# SPace USage (and apparently the Romanian work for "ready" or
# "willing") to avoid confusion with a similarly named script by
# a fellow called John Vromans as well as a similar utility for
# NetWare.
# o Uses #!/bin/sh shebang at beginning of script to accommodate
# varying locations of 'perl'.
# o Fixed yet another bug with space handling, this time while
# viewing the contents of a directory whose name contains spaces.
#
# 2.1 o Starting using 'sccs' to manage code.
# o Fixed incorrect counting of mount points. An empty array has
# -1 items, not 0.
#
# 1.9 o Fixed handling of filenames with spaces by always using branch
# that handles ignoring mount points.
#
# 1.8 o Slight change to 'du' options selection based on OS (for Cygwin).
# o Changed to display correct values from 'df'.
#
# 1.7 o Hidden files not listed. Found a way to fix using an `ls` but
# runs into the filenames with spaces bug again.
# o Include free space on filesystem after current directory name.
#
# 1.6 o Fixed bug with determining mount points under Linux (Solaris
# says "(filesystem) on (device)" unless you use 'mount -v',
# in which case the sense is reversed, like Linux).
# o Accommodated different auto master filename on Linux.
#
# 1.5 o Reads /etc/auto_master to establish further mount points to
# ignore.
#
# 1.4 o Displays 'Ignoring mount points:' if the current directory
# is a mount point, though it may not contain any. - bug fixed.
#
# 1.3 o Code improvements (use /string/i in regexp matches).
# o Ignore mount points in any directory.
#
# 1.2 o Accept 'c' or 'cd' and a parameter.
# o Remembered to increment version number.
# o "!shell command"
#
# 1.1 o Accept 'quit', 'exit'.
# o Changed '.' command to reread usage in current directory in
# case files have been deleted.
#
# 1.0 o Linux compatibility (different du switches).
#
# 0.9 o Ignore mount points in root directory.
#
# 0.8 o Used KB (Bytes) instead of Kb (Kilobits).
# o Added -d switch to du to restrict it to that particular
# filesystem.
# o Added 'k' command to start Korn shell instead of Bourne as
# root's SHELL variable always seems to be '/bin/sh' regardless.
#
# 0.7 o Directories containing a space in their name are not handled
# correctly by the split. - fixed.
# o Fixed prompt on invalid selection.
# o Terminated 'du' command with -- to handle files beginning with
# '-' character.
#
# 0.6 o Included help, new prompt, shell function.
# o Started version history.
# Initialise a few things.
sub init {
$version="dispus v2.6";
$S_IFDIR=0x4000;
$PROMPT="\ndispus> ";
# Number of lines used on screen apart from actual file listing.
$linesreserved=6;
# Set $pagelength by using:
# - the LINES environment variable,
# - 'stty rows' value or
# - the default value, in that order.
$pagelength=$ENV{"LINES"};
if (!defined($pagelength)) {
open(STTY,"stty -a |") || die "Error running stty: $!";
while () {
/rows (= )*([0-9]+)/;
if (defined($2)) { $pagelength=$2 };
}
close(STTY);
}
if (!defined($pagelength)) { $pagelength=24 };
# Set OS dependent variables.
chomp($os=`uname`);
if ($os eq "AIX"){
$du="du -ks -- ";
# VERIFY
$automaster="/etc/auto_master";
$mount="mount | ";
} elsif ($os eq "HP-UX"){
$du="du -xks -- ";
$automaster="/etc/auto_master";
$mount="mount -v | "
} elsif ($os eq "Linux") {
$du="du -xks -- ";
$automaster="/etc/auto.master";
$mount="mount -v | "
} elsif ($os eq "OSF1"){
$du="du -xks -- ";
$automaster="/etc/auto.master";
$mount="mount | "
} elsif ($os eq "MacOS") {
$du="du -ks -- ";
$automaster="/etc/auto_master";
$mount="mount -v | "
} elsif ($os eq "SunOS"){
$du="du -dks -- ";
$automaster="/etc/auto_master";
$mount="mount -v | "
} else {
$du="du -ks -- ";
$automaster="/etc/auto_master";
$mount="mount -v | "
}
open(MOUNTPOINTS, $mount) or die "Error running mount: $!";
$i=0;
if ($os eq "AIX") {
# Always ignore the /tmp_mnt filesystem.
$mountpoints[$i++]="/tmp_mnt";
; # Skip first two lines (column headings)
;
while () {
# Account for lines with empty node (first) column.
if (/^ +[^ ]+ +([^ ]+) /) { $mountpoints[$i++]=$1; }
# Account for lines with non-empty node column,
# e.g. NFS mounts.
if (/^[^ ]+ +[^ ]+ +([^ ]+) /) { $mountpoints[$i++]=$1; }
}
} else {
while () {
if (/^.*\son\s(\/.*?)?\s.+\n/) { $mountpoints[$i++]=$1; }
}
}
close(MOUNTPOINTS);
if (open(MOUNTPOINTS, $automaster)) {
while () {
if (/^(\/.*?)\s.+$/) { $mountpoints[$i++]=$1; }
}
close(MOUNTPOINTS);
}
}
# Put commas in number(s) to make them easy to read.
sub commas {
return unless defined wantarray; # void context, do nothing
my @parms = @_;
for (@parms) {
if ($_ =~ s/(\d+)(\d\d\d)$/$1,$2/ == 1) {
until ( ($_ =~ s/(\d+)(\d\d\d),/$1,$2,/) != 1) { };
}
}
return wantarray ? @parms : $parms[0];
}
# Run du and populate @usage and @dirname.
sub readusage {
chomp($cwd=`pwd`);
print("$version - Reading usage in ",$cwd,"\n");
# Determine whether there are any mountpoints in the current
# directory.
$i=0;
@cwdmountpoints=();
foreach (@mountpoints) {
if ($cwd eq "/" && m@^/([^/]+)$@) {
$cwdmountpoints[$i++] = $1;
} elsif (m@^$cwd/([^/]+)$@) {
$cwdmountpoints[$i++] = $1;
}
}
# Ignore any mountpoints in the current directory.
open(LS, "ls -d -- * .[!.]* 2> /dev/null |")
or die "Error running ls: $!";
chomp(@files=());
close(LS);
foreach (@files) {
# Escape backslashes, double-quotes, dollar signs and
# backquotes.
s/([\\"\$`])/\\$1/g;
# Surround filename in quotes if it contains other shell
# metacharacters.
s/^(.*[<>|;'() ].*)$/\"$1\"/;
}
if ($#cwdmountpoints >= 0) {
print "Ignoring mount points:";
foreach (@cwdmountpoints) {
for ($i=0; $i <= $#files; $i++) {
# Remove any mount points.
if ($files[$i] eq $_) {
splice(@files,$i,1);
print " $_"
}
}
}
print "\n";
}
$ducmd = $du . join(" ",@files) . " | sort -n -r |";
open(DUKS, $ducmd) or die "Error running du: $!";
@duks=();
close(DUKS);
chomp(@duks);
$i=1;
$#usage=0;
foreach (@duks) {
/([0-9]+)\s+(.*)/;
$usage[$i] = $1;
$dirname[$i] = $2;
$i++;
}
$topofpage=1;
}
# Display the contents of @usage and @dirname neatly.
sub displaydusage {
$i=$topofpage;
printf("\n");
if ($topofpage==1) {
$templinesreserved=$linesreserved + 2;
# Display space used on this filesystem.
if ($os eq "HP-UX") {
# Cater for HP-UX' multiple-line 'bdf' output.
open(DF, "/usr/bin/bdf $cwd 2> /dev/null |") or die "Error running /usr/bin/bdf: $!";
; # Skip first line (column headings)
while () {
chop($_);
s/^ +//;
@arr = split(/ +/, $_);
if ($#arr == 0) { next ; }
if ($#arr == 4) { $used=$arr[1] ; $tot=$arr[0] ; $per=$arr[3]; }
else { $used=$arr[2] ; $tot=$arr[1] ; $per=$arr[4]; }
print(" " . commas($used) . " KB used of " . commas($tot)
. " KB available ($per)\n\n");
}
} else {
open(DF, "df -k $cwd 2> /dev/null | ") or die "Error running df: $!";
while () {
if (/^.* +([0-9]+) +([0-9]+) +[0-9]+ +([0-9]+%)/) {
print(" " . commas($2) . " KB used of " . commas($1)
. " KB available ($3)\n\n");
}
}
}
close(DF);
} else {
$templinesreserved=$linesreserved;
}
while ($i <= $#usage
&& $i-$topofpage < $pagelength-$templinesreserved) {
$mode = (stat($dirname[$i]))[2];
if ( defined($mode) && ($S_IFDIR & $mode)) {
printf("%4d. %10s KB %s\n",$i,commas($usage[$i]),$dirname[$i]);
} else {
printf(" %10s KB %s\n",commas($usage[$i]),$dirname[$i]);
}
$i++;
}
$i--; # Undo the overrun.
print "\n $topofpage to $i of $#usage shown ? - help";
if ($i != $#usage) { print " f - forward" };
if ($topofpage != 1) { print " b - back" };
print " q - quit\n";
}
# Main code.
init;
if ($#ARGV >= 0) {
chdir($ARGV[0]) || die "Unable to change directory to $ARGV[0]: $!";
}
readusage;
displaydusage;
print $PROMPT;
WHILE: while () {
chomp;
CASE: {
/^\?$/ && do {
print "\n";
print "? Display this help\n";
print "0-9+ Traverse selected directory\n";
print ". Redisplay current directory\n";
print ".. Traverse parent directory\n";
print "c [dir] Change to specific directory\n";
print "f Page forward\n";
print "b Page back\n";
print "q Quit\n";
print "s Start \$SHELL in current directory\n";
print "k Start /bin/ksh in current directory\n";
print "![cmd] Run command 'cmd' (or shell if omitted) in current directory\n";
last CASE;
};
/^[0-9]+$/ && do {
print "\n";
chdir($dirname[$_]);
readusage;
displaydusage;
last CASE;
};
/^\.$/ && do {
readusage;
displaydusage;
last CASE;
};
/^\.\.$/ && do {
chdir("..");
readusage;
displaydusage;
last CASE;
};
/^cd?( (.+))?$/i && do {
if (defined($2)) {
$newdir=$2;
} else {
print "Enter directory to change to: ";
chomp($newdir=);
}
if (chdir($newdir)) {
readusage;
displaydusage;
} else {
print "chdir to $newdir failed!\n";
}
last CASE;
};
/^b$/i && do {
$topofpage=$topofpage-($pagelength-$linesreserved);
if ($topofpage < 1) { $topofpage=1 }
displaydusage;
last CASE;
};
/^f$/i && do {
$topofpage=$i;
displaydusage;
last CASE;
};
/^k$/i && do {
system "/bin/ksh";
displaydusage;
last CASE;
};
/^[s!](.+)?$/i && do {
if (defined($1)) {
system($1);
} else {
system "\$SHELL";
displaydusage;
}
last CASE;
};
/^(q.*|exit|x)$/i && do { last WHILE; };
print "Invalid selection! ? for help.\n";
}
print $PROMPT;
}
print "\n";
Wednesday, July 16, 2025
dispus
sometimes i need to know where space is being used. i've used this for a decade and don't know where to find it. so. yeah.
Subscribe to:
Comments (Atom)