Article 344 of alt.sources:
Path: lightnin!rwsys!utacfd.uta.edu!news.oc.com!mercury.unt.edu!cs.utexas.edu!wupost!uunet!mcsun!uknet!pavo.csi.cam.ac.uk!nntp-serv.cam.ac.uk!tdw
From: tdw@uk.ac.cam.cl (Tim Wilson)
Newsgroups: alt.sources
#Subject: Another stat program (perl script)
Message-ID: <TDW.92Oct5124326@ramsey.uk.ac.cam.cl>
Date: 5 Oct 92 12:43:26 GMT
Sender: news@infodev.cam.ac.uk (USENET news)
Organization: University of Cambridge Computer Laboratory, UK
Lines: 307
Nntp-Posting-Host: ramsey.cl.cam.ac.uk

Here's another stat command.

Use the -l flag to examine symbolic links (instead of the linked-to file).

This version of stat one has two output formats.  
The default is human-readable, eg

$ stat stat
stat
	device		0x5526
	inode		23068		0x5a1c
	mode		-r-xr-xr-x	0100555
	nlink		1
	owner		tdw
	group		private
	rdev		-1
	size		6707
	atime		Mon Oct  5 12:31:57 1992
	mtime		Mon Oct  5 11:53:48 1992
	ctime		Mon Oct  5 11:53:48 1992
	blksize		8192
	blocks		14

but there is also a numeric output format that is useful for forther
processing, eg

$ stat -n stat
stat 0x5526 0x5a1c 0100555 1 1007 19 0xffffffff 6707 718284717 718282428 718282428 8192 14

The fields are:
device inode mode nlink uid gid rdev size {a,m,c}time blocksize blocks.

I hope someone finds this useful.
If you have any comments or suggestions, please let me know.

Tim
--
Tim Wilson   tdw@cl.cam.ac.uk   University of Cambridge Computer Laboratory, UK
--- CUT HERE -----------------------------------------------------------------
# /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  stat
# Wrapped by tdw@ramsey.cl.cam.ac.uk on Mon Oct  5 12:31:57 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'stat' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stat'\"
else
echo shar: Extracting \"'stat'\" \(6707 characters\)
sed "s/^X//" >'stat' <<'END_OF_FILE'
X#!/usr/bin/perl
X#
X# Last edited: Mon Oct  5 11:48:02 1992 by Tim Wilson
X# $Id: stat,v 1.1 1992/10/05 10:53:13 tdw Exp $
X#
X# Stat(2) files and print results.
X#
X# Usage: stat [-?] [-l] [-n] [-h] [--] files...
X#
X#  -l: use lstat(2) instead of stat(2)
X#  -n: print output in numeric format (instead of readable format)
X#  -h: if in numeric format, also print header line
X#  -?: print help message
X#  --: remaining arguments are file names
X#
X######################################################################
X#
X# Copyright (C) 1992 T D Wilson.  All rights reserved.
X#
X# Permission to copy without fee all or part of this material is
X# granted provided that the copies are not made or distributed for
X# direct commercial advantage, the copyright notice and the title and
X# date appear, and notice is given that copying is by permission of
X# the author.  To copy otherwise, or to republish, requires specific
X# permission.
X#
X# T D Wilson makes no representations about the suitability of this
X# software for any purpose.  It is provided "as is" without express or
X# implied warranty.
X#
X######################################################################
X#
X# Modification summary:
X#   5 Oct 1992	Tim Wilson	Altered comments; posted to
X#				alt.sources.  Revision 1.1.
X#  11 Jul 1991	Tim Wilson	Created.
X#
X# Tim Wilson, University of Cambridge Computer Laboratory, UK.
X# tdw@cl.cam.ac.uk
X#
X
Xsub usage {
X	die "Usage: $progname [-l] [-n] [-h] [--] files...\n";
X}
X
Xsub Lstat {
X    ($st_dev,$st_ino,$st_mode,$st_nlink,$st_uid,$st_gid,$st_rdev,$st_size,
X	$st_atime,$st_mtime,$st_ctime,$st_blksize,$st_blocks) = lstat(shift(@_));
X}
X
Xrequire "stat.pl";
Xrequire "ctime.pl";
X
X######################################################################
X#
X# p_perm -- Return part permissions symbolically
X#
X#  perm:	Permissions.  Only the low three bits are significant
X#  extra:	Extra bit to be encoded with execute (suid, sgid, sticky)
X#  c:		Character to be used instead of `x' (`s' or `t')
X#
X# Returns -- three character string
X#
X# Side effects -- Output
X#
X######################################################################
X
Xsub p_perm {
X	local ($perm,$extra,$c) = @_;
X	local ($lower,$upper) = ($c, $c);
X	local ($result);
X	$lower =~ tr/ST/st/; # Guaranteed lower case `s' or `t'
X	$upper =~ tr/st/ST/; # Guaranteed upper case `S' or `T'
X
X	$result = ($perm & 04) ? "r" : "-";
X	$result .= ($perm & 02) ? "w" : "-";
X	# Want 2D array; do index arithmetic ourselves
X	$result .= ("-", "x", $upper, $lower)[!!$extra * 2 + ($perm & 01)];
X}
X
X
X######################################################################
X#
X# p_mode -- Return symbolic $st_mode (and/or memorized stat structure)
X#
X#  Arguments are global variables.  Ahem!
X#
X# Returns -- ten character string
X#
X# Side effects -- Output
X#
X######################################################################
X
Xsub p_mode {
X	local ($result);
X	# First letter according to type of file
X	TYPE: {
X		-p _ && do {$result = "p"; last TYPE;};
X		-c _ && do {$result = "c"; last TYPE;};
X		-d _ && do {$result = "d"; last TYPE;};
X		-b _ && do {$result = "b"; last TYPE;};
X		-l $file && do {$result = "l"; last TYPE;};# lstat problems
X		-f _ && do {$result = "-"; last TYPE;};
X		-S _ && do {$result = "s"; last TYPE;};
X		warn ("unknown type of file, mode %#o\n", $st_mode);
X		$result = "?";
X	}
X
X	$result .= &p_perm ($st_mode >> 6, -u _, "s");	# User
X	$result .= &p_perm ($st_mode >> 3, -g _, "s");	# Group
X	$result .= &p_perm ($st_mode >> 0, -k _, "t");	# Others
X}
X
X
X######################################################################
X#
X# uid, gid -- Convert numeric uid, gid to symbolic
X#
X#  arg:		numeric id
X#
X# Returns -- Name associated with id if found, else number
X#
X# Side effects -- Accesses /etc/passwd or replacement
X#
X######################################################################
X
Xsub uid {
X	local ($uid) = @_;
X	local ($name) = getpwuid ($uid);
X
X	defined ($name) ? return $name : return $uid;
X}
X
Xsub gid {
X	local ($gid) = @_;
X	local ($name) = getgrgid ($gid);
X
X	defined ($name) ? return $name : return $gid;
X}
X
X
X######################################################################
X#
X# verbstat -- Print $st_* variable (and/or remembered stat structure)
X#             in multiline verbose format
X#
X#  Arguments are global variables.  Ahem!
X#
X# Returns -- nothing
X#
X# Side effects -- Output
X#
X######################################################################
X
Xsub verbstat {
X	local ($atime, $mtime, $ctime) 
X		= (&ctime ($st_atime), &ctime ($st_mtime), &ctime ($st_ctime));
X	local ($mode) = &p_mode;
X
X	printf ("%s\n", $file);
X	printf ("\tdevice\t\t%#x\n", $st_dev);
X	printf ("\tinode\t\t%d\t\t%#x\n", $st_ino, $st_ino);
X	printf ("\tmode\t\t%s\t%#o\n", &p_mode, $st_mode);
X	printf ("\tnlink\t\t%d\n", $st_nlink);
X	printf ("\towner\t\t%s\n", &uid ($st_uid));
X	printf ("\tgroup\t\t%s\n", &gid ($st_gid));
X	printf ("\trdev\t\t%d\n", $st_rdev);
X	printf ("\tsize\t\t%d\n", $st_size);
X	chop ($atime);
X	chop ($mtime);
X	chop ($ctime);
X	printf ("\tatime\t\t%s\n\tmtime\t\t%s\n\tctime\t\t%s\n",
X		$atime, $mtime, $ctime);
X	printf ("\tblksize\t\t%d\n", $st_blksize);
X	printf ("\tblocks\t\t%d\n", $st_blocks);
X}
X
X
X######################################################################
X# Main program
X######################################################################
X
X$_ = $0;
X$progname = m|.*/([^/]+)| ? $1 : $_;
X
X
X$opt_lstat = 0;				# If true use lstat not stat
X$opt_header = 0;			# Add header line
X$opt_numeric = 0;			# One-line numeric format
X
X# No switch clustering with this simple parser
X
XSWITCH:
Xwhile ($_ = shift) {
X	/^-\?/ && &usage;			# stat -? ... gives usage
X	/^--$/ && last SWITCH;			# -- terminates switches
X	/^-l$/ && ($opt_lstat = 1, next SWITCH);
X	/^-h$/ && ($opt_header = 1, next SWITCH);
X	/^-n$/ && ($opt_numeric = 1, next SWITCH);
X
X	unshift (ARGV, $_);		# We are looking at the first file
X	last SWITCH;
X}
X
X($#ARGV < $[) && &usage;		# Must have at least one arg
X
X
X# Print out header if requested and numeric format
X
X$opt_numeric && $opt_header && print "dev ino mode nlink uid gid rdev size atime mtime ctime blksize blocks\n";
X
X
X# Stat remaining args and print result
X
Xforeach $file (@ARGV) {
X	if ($opt_lstat) {
X		&Lstat ($file);
X	} else {
X		&Stat ($file);
X	}
X
X	if (defined ($st_dev)) {
X		if ($opt_numeric) {
X			#       fn  dev ino md  nl ud gd rdv siz atm mtm ctm bks nbk
X			printf "%s %#x %#x %#o %d %d %d %#x %ld %ld %ld %ld %d %d\n",
X			$file,
X			$st_dev, $st_ino, $st_mode, $st_nlink, 
X			$st_uid, $st_gid,
X			$st_rdev, $st_size, 
X			$st_atime, $st_mtime, $st_ctime,
X			$st_blksize, $st_blocks;
X		} else {
X			&verbstat;
X		}
X	} else {
X		$opt_lstat ?
X			warn $file, ": Can't lstat\n" :
X			warn $file, ": Can't stat\n";
X	}
X}
X
X# End of stat
END_OF_FILE
if test 6707 -ne `wc -c <'stat'`; then
    echo shar: \"'stat'\" unpacked with wrong size!
fi
chmod +x 'stat'
# end of 'stat'
fi
echo shar: End of shell archive.
exit 0
--
Tim Wilson   tdw@cl.cam.ac.uk   University of Cambridge Computer Laboratory, UK


