#!/usr/bin/perl -w my $rcsid = '$Id: stat,v 1.3 2009/09/09 17:42:19 vogelke Exp $'; =head1 NAME stat =head1 SYNOPSIS stat [-abcdghimnprstuv] file [file...] =head1 DESCRIPTION Prints the output from stat() for all files on the command line. Here are the fields from a stat call: index name description ------------------------------------------------------------------- 0 dev device number of filesystem 1 ino inode number 2 mode file mode (type and permissions) 3 nlink number of (hard) links to the file 4 uid numeric user ID of file's owner 5 gid numeric group ID of file's owner 6 rdev the device identifier (special files only) 7 size total size of file, in bytes 8 atime last access time in seconds since the epoch 9 mtime last modify time in seconds since the epoch 10 ctime inode change time in seconds since the epoch (*) 11 blksize preferred block size for file system I/O 12 blocks actual number of blocks allocated =head1 OPTIONS You can restrict the output by using these command line options: Option Will print ------------------------------------------------------------------- -a last access time in seconds since the epoch -b actual number of blocks allocated -c inode change time in seconds since the epoch (*) -d device number of filesystem -g numeric group ID of file's owner -i inode number -m last modify time in seconds since the epoch -n number of (hard) links to the file -p file mode (type and permissions) -r the device identifier (special files only) -s total size of file, in bytes -t last modify time, in form of "touch -d" command -u numeric user ID of file's owner -v prints the version and exits. =head1 AUTHOR Karl Vogel Sumaria Systems, Inc. =cut use strict; use subs qw(strmode usage version); use Getopt::Std; use File::Basename; use Fcntl ':mode'; use POSIX qw(asctime); my ($myname) = basename($0, ".pl"); my @result; #--------------------------------------------------------------------- # Set the name for each field, and a list for which fields are wanted # by the user. For example, "choices" shows that command line option # "-a" prints field 8 from the output of stat(), which (according to # fields) is the atime. my %fields = qw( 0 device: 1 inode: 2 mode: 3 nlink: 4 uid: 5 gid: 6 rdev: 7 size: 8 atime: 9 mtime: 10 ctime: 11 blksize: 12 blocks: ); my %choices = qw( a 8 b 12 c 10 d 0 g 5 i 1 m 9 n 3 p 2 r 6 s 7 t 9 u 4 ); my %wanted = (); # Empty unless only specific fields are wanted. #--------------------------------------------------------------------- # Handle arguments. my %opts; getopts('abcdghimnprstuv', \%opts) or usage(); if ($opts{v}) { warn version(), "\n"; exit(0); } if ($opts{h} or !@ARGV) { usage(); } my $val; foreach (keys %opts) { $val = $choices{$_}; $wanted{$val} = 1; } # # Stat each file. # my $k; my $loop = 0; foreach my $f (@ARGV) { if (@result = stat($f)) { # print the mode in octal, and like "ls -l" $k = sprintf("%lo", S_IMODE($result[2])); $_ = strmode($result[2]); $result[2] = "$k ($_)"; # print readable times. chomp($_ = asctime(localtime($result[8]))); $result[8] .= " ($_)"; chomp($_ = asctime(localtime($result[10]))); $result[10] .= " ($_)"; # either print just certain fields, like size, etc... if (%wanted) { chomp($_ = asctime(localtime($result[9]))); if ($opts{t}) { print "touch -d '$_' $f\n"; } else { $result[9] .= " ($_)"; foreach $k (keys %wanted) { print "$f\t$fields{$k} $result[$k]\n"; } } } # ... or print everything stat returns. else { chomp($_ = asctime(localtime($result[9]))); $result[9] .= " ($_)"; print "$f:\n"; for ($k = 0 ; $k <= $#result ; $k++) { printf "%10s %s\n", $fields{$k}, $result[$k]; } print "\n" unless $loop == $#ARGV; } } else { warn "$f: $!\n"; next; } $loop++; } exit(0); #--------------------------------------------------------------------- # Print a usage message from the comment header and exit. sub usage { my ($emsg) = @_; require Pod::Text; import Pod::Text; my $formatter = 'Pod::Text'; my $parser = $formatter->new(); warn "$myname: $emsg\n\n" if $emsg; $parser->parse_from_file($0); exit(1); } #--------------------------------------------------------------------- # Return the current version. sub version { return sprintf("%s v%d.%02d %s %s", $rcsid =~ /(\S+),v (\d+)\.(\d+) (\S+) (\S+)/); } #--------------------------------------------------------------------- # Print a nice mode. sub strmode { my ($mode) = @_; my @modemap = ( 0400 => 'r', # R for owner 0200 => 'w', # W for owner 0100 => 'x', # X for owner 0040 => 'r', # R for group 0020 => 'w', # W for group 0010 => 'x', # X for group 0004 => 'r', # R for other 0002 => 'w', # W for other 0001 => 'x' ); # X for other my $modestr = ''; # Filetype $modestr = '-' if S_ISREG($mode); $modestr = 'd' if S_ISDIR($mode); $modestr = 'l' if S_ISLNK($mode); $modestr = 's' if S_ISSOCK($mode); $modestr = 'b' if S_ISBLK($mode); $modestr = 'c' if S_ISCHR($mode); $modestr = 'p' if S_ISFIFO($mode); # $modestr = 'w' if S_ISWHT($mode); $mode &= 0777; # just the RWX bits. while (@modemap) { my ($bit, $letter) = splice(@modemap, 0, 2); if ($mode & $bit) { $modestr .= $letter; } else { $modestr .= "-"; } } return "$modestr"; }