
![]() | ![]() |
9.13. Program: lst
Have
you ever wondered what the newest or biggest files within a directory
are? The standard ls program has options for
listing out directories sorted in time order (the -t flag) and for recursing into subdirectories
(the -R flag). However, it pauses at
each directory to display the sorted contents of just that directory.
It doesn't descend through all subdirectories first and then sort
everything it found.The following lst program does that. Here's an
example using its -l flag to get a
long listing:% lst -l /etc
12695 0600 1 root wheel 512 Fri May 29 10:42:41 1998
/etc/ssh_random_seed
12640 0644 1 root wheel 10104 Mon May 25 7:39:19 1998
/etc/ld.so.cache
12626 0664 1 root wheel 12288 Sun May 24 19:23:08 1998
/etc/psdevtab
12304 0644 1 root root 237 Sun May 24 13:59:33 1998
/etc/exports
12309 0644 1 root root 3386 Sun May 24 13:24:33 1998
/etc/inetd.conf
12399 0644 1 root root 30205 Sun May 24 10:08:37 1998
/etc/sendmail.cf
18774 0644 1 gnat perldoc 2199 Sun May 24 9:35:57 1998
/etc/X11/XMetroconfig
12636 0644 1 root wheel 290 Sun May 24 9:05:40 1998
/etc/mtab
12627 0640 1 root root 0 Sun May 24 8:24:31 1998
/etc/wtmplock
12310 0644 1 root tchrist 65 Sun May 24 8:23:04 1998
/etc/issue
....
/etc/X11/XMetroconfig showed up in the middle of
the listing for /etc because it wasn't just for
/etc, but for everything within that directory,
recursively.Other supported options include sorting on read time instead of write
time using -u and sorting on size
rather than time with -s. The
-i flag takes the list of filenames
from standard input instead of recursing with
find. That way, if you already had a list of
filenames, you could feed them to lst for
sorting.The program is shown in Example 9-7.
Example 9-7. lst
#!/usr/bin/perl
# lst - list sorted directory contents (depth first)
use Getopt::Std;
use File::Find;
use File::stat;
use User::pwent;
use User::grent;
getopts("lusrcmi") or die << DEATH;
Usage: $0 [-mucsril] [dirs ...]
or $0 -i [-mucsrl] < filelist
Input format:
-i read pathnames from stdin
Output format:
-l long listing
Sort on:
-m use mtime (modify time) [DEFAULT]
-u use atime (access time)
-c use ctime (inode change time)
-s use size for sorting
Ordering:
-r reverse sort
NB: You may only use select one sorting option at a time.
DEATH
unless ($opt_i || @ARGV) { @ARGV = (".") }
if ($opt_c + $opt_u + $opt_s + $opt_m > 1) {
die "can only sort on one time or size";
}
$IDX = "mtime";
$IDX = "atime" if $opt_u;
$IDX = "ctime" if $opt_c;
$IDX = "size" if $opt_s;
$TIME_IDX = $opt_s ? "mtime" : $IDX;
*name = *File::Find::name; # forcibly import that variable
# the $opt_i flag tricks wanted into taking
# its filenames from ARGV instead of being
# called from find.
if ($opt_i) {
*name = *_; # $name now alias for $_
while (<>) { chomp; &wanted; } # ok, not stdin really
} else {
find(\&wanted, @ARGV);
}
# sort the files by their cached times, youngest first
@skeys = sort { $time{$b} <=> $time{$a} } keys %time;
# but flip the order if -r was supplied on command line
@skeys = reverse @skeys if $opt_r;
for (@skeys) {
unless ($opt_l) { # emulate ls -l, except for permissions
print "$_\n";
next;
}
$now = localtime $stat{$_}->$TIME_IDX( );
printf "%6d %04o %6d %8s %8s %8d %s %s\n",
$stat{$_}->ino( ),
$stat{$_}->mode( ) & 07777,
$stat{$_}->nlink( ),
user($stat{$_}->uid( )),
group($stat{$_}->gid( )),
$stat{$_}->size( ),
$now, $_;
}
# get stat info on the file, saving the desired
# sort criterion (mtime, atime, ctime, or size)
# in the %time hash indexed by filename.
# if they want a long list, we have to save the
# entire stat object in %stat. yes, this is a
# hash of objects
sub wanted {
my $sb = stat($_); # XXX: should be stat or lstat?
return unless $sb;
$time{$name} = $sb->$IDX( ); # indirect method call
$stat{$name} = $sb if $opt_l;
}
# cache user number to name conversions; don't worry
# about the apparently extra call, as the system caches the
# last one called all by itself
sub user {
my $uid = shift;
$user{$uid} = getpwuid($uid) ? getpwuid($uid)->name : "#$uid"
unless defined $user{$uid};
return $user{$uid};
}
# cache group number to name conversions; ditto on unworryness
sub group {
my $gid = shift;
$group{$gid} = getgrgid($gid) ? getgrgid($gid)->name : "#$gid"
unless defined $group{$gid};
return $group{$gid};
}
![]() | ![]() | ![]() |
9.12. Program: symirror | ![]() | 10. Subroutines |

Copyright © 2003 O'Reilly & Associates. All rights reserved.