This isn't done, but I had it lying around, and it's *almost* done. It emulates `ls -l' *only*. I put considerable work into making it exactly compatible with the real ls -l. Since the rest of ls is mostly sorting options, and a thing to display output in columns, it should be pretty easy to turn this into a clone of the full ls. Hint hint. It requires Stat::lsMode. http://www.plover.com/~mjd/perl/lsMode/ http://www.perl.com/CPAN/authors/id/MJD/Stat-lsMode-0.50.tar.gz #!/usr/bin/perl # # ls-l # # mjd-perl-ppt@plover.com # use Stat::lsMode qw(format_mode); my @mon = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); my @files = @ARGV ? @ARGV : qw(.); my @lines; for (grep {-l || ! -d} @files) { my ($blocks, $line) = do_file($_); push @lines, $line; } print map {$_->[1]} sort {$a->[0] cmp $b->[0]} @lines; foreach $f (grep {-d && ! -l} @files) { if (opendir DIR, $f) { print "\n", $f, ":\n" unless @files == 1; ($blocks, @lines) = do_files($f, readdir DIR); closedir DIR; } else { warn "ls: $f: $!\n"; } print "total $blocks\n"; print map {$_->[1]} sort {$a->[0] cmp $b->[0]} @lines; } sub do_file { my $file = shift; my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = lstat $file; unless (defined $dev) { warn "ls: $_: $!\n"; next; } my $perms = format_mode($mode); my $name = $_; if ($perms =~ /^l/) { my $link = readlink "$dir/$_"; $name = "$name -> $link"; } my $date = format_time($mtime); my ($u, $g) = ui($uid, $gid); ( $blocks, [$name, sprintf("%s %3d %-8s %-8s %8d %s %s\n", $perms, $nlink, $u, $g, $size, $date, $name, ) ] ); } sub do_files { my $dir = shift; my $tot_blocks = 0; for (@_) { next if /^\./; my ($blocks, $line) = do_file("$dir/$_"); $tot_blocks += $blocks; push @lines, $line; } ($tot_blocks/2, @lines); } sub ui { my ($u, $g) = @_; $u = ($u{$u} ||= getpwuid($u)); $g = ($g{$g} ||= getgrgid($g)); ($u, $g); } # Date formats: # Recent: Mmm dd hh:mm (day space-filled; hour zero-filled T24) $daterecent = '%b %d %H:%M'; # Older: Mmm dd yyyy $dateolder = '%b %d %Y'; sub format_time { my $time = shift; return $time{$time} if exists $time{$time}; my $timestr; my @time = localtime($time); my ($sec, $min, $hour, $day, $mon, $year) = localtime($time); if ($time < $^T - 180*24*3600 || $time > $^T + 3600) { $timestr = sprintf "$mon[$mon] %2d %4d", $day, $year+1900; } else { $timestr = sprintf "$mon[$mon] %2d %02d:%02d", $day, $hour, $min; } $time{$time} = $timestr; }