Hi there,
On Unix, is there a command to display a file's modification time, precise to the second?
On Linux this is easily done with a "stat -c %y", which returns something like 2009-11-27 11:36:06.000000000 +0100. I found no equivalent on Unix.
Hi there,
On Unix, is there a command to display a file's modification time, precise to the second?
On Linux this is easily done with a "stat -c %y", which returns something like 2009-11-27 11:36:06.000000000 +0100. I found no equivalent on Unix.
According to the man page on my Mac (which has the BSD standard version of stat) you can get the epoch time version of the modification in seconds with:
stat -f %m /etc/passwd
Or if you want to print that out in hours:mins:secs you can do this:
perl -e "print scalar(localtime(`stat -f %m /etc/passwd`))"
For anyone facing the same issue, I found no solution (on HP-UX 11i anyway). Ended up coding a personalized "ls -lh" for my needs. It's not that hard.. Prints something like :
- 664 rw-/rw-/r-- 1L expertNoob adm 8.37 kB 2010.08.24 12:11:15 findf1.c
d 775 rwx/rwx/r-x 2L expertNoob adm 96 B 2010.08.24 15:17:37 tmp/
- 775 rwx/rwx/r-x 1L expertNoob adm 16 kB 2010.08.24 12:35:30 findf1
- 775 rwx/rwx/r-x 1L expertNoob adm 24 kB 2010.09.14 19:45:20 dir_info
- 444 r--/r--/r-- 1L expertNoob adm 9.01 kB 2010.09.01 11:23:41 getopt.c
- 664 rw-/rw-/r-- 1L expertNoob adm 6.86 kB 2010.09.01 11:24:47 getopt.o
- 664 rw-/rw-/r-- 1L expertNoob adm 6.93 kB 2010.09.14 19:37:44 findf1.o
l 775 rwx/rwx/r-x 1L expertNoob adm 6 B 2010.10.06 17:09:01 test1 -> test.c
- 664 rw-/rw-/r-- 1L expertNoob adm 534 B 2009.03.26 15:34:23 > test.c
d 755 rwx/r-x/r-x 25L expertNoob adm 8 kB 2009.05.20 15:36:23 zip30/
Here it is :
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <locale.h>
#include <langinfo.h>
#include <stdio.h>
//#include <stdint.h>
#include <limits.h> // PATH_MAX
#include <stdarg.h>
#include "getopt.h"
static short START_VSNBUFF=16;
// This is bformat from Better String library (bstrlib), customized
int strformat (char ** str, const char * fmt, ...) {
va_list arglist;
char * buff;
int n, r;
/* Since the length is not determinable beforehand, a search is
performed using the truncating "vsnprintf" call (to avoid buffer
overflows) on increasing potential sizes for the output result. */
if ((n = (int) (2*strlen (fmt))) < START_VSNBUFF) n = START_VSNBUFF;
if ( NULL == ( buff = (char *) malloc((n + 2)*sizeof(char)) ) ) {
n = 1;
if ( NULL == ( buff = (char *) malloc((n + 2)*sizeof(char)) ) ) {
fprintf( stderr, "strformat: not enough memory to format string\n" );
return -1;
}
}
for (;;) {
va_start (arglist, fmt);
r = vsnprintf (buff, n + 1, fmt, arglist); // n+1 chars: buff[0]..buff[n], n chars from arglist: buff[n]='\0'
va_end (arglist);
buff[n] = (unsigned char) '\0'; // doesn't hurt, especially strlen!
if ( strlen(buff) < n ) break;
if (r > n) n = r; else n += n;
if ( NULL == ( buff = (char *) realloc( buff, (n + 2)*sizeof(char) ) ) ) {
free(buff);
fprintf( stderr, "strformat: not enough memory to format string\n" );
return -1;
}
}
if( NULL != *str ) free(*str);
*str = buff;
return 0;
}
int printFSObjectInfo( const char * path, const char * name ) {
struct stat statbuf;
struct passwd *pwd;
struct group *grp;
struct tm *tm;
char datestring[256];
char *type = "? ";
char *fbuf = NULL;
double size = 0;
const char *units[] = {"B ", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
int i = 0;
char owner[] = "---", group[] = "---", others[] = "---";
/* Get entry's information. */
if ( -1 == lstat( path, &statbuf ) ) {
fprintf( stderr, "printFSObjectInfo: error: can't stat %s\n", path );
if( 0 == strformat( &fbuf, "lstat() said: %s", path ) ) { perror(fbuf); return -1; }
}
// File type
if( S_ISREG(statbuf.st_mode) ) type = "-"; // regular file
if( S_ISDIR(statbuf.st_mode) ) { // directory
type="d";
if( S_ISCDF(statbuf.st_mode) ) type = "hd"; // hidden dir
}
if( S_ISBLK(statbuf.st_mode) ) type = "b"; // block special
if( S_ISCHR(statbuf.st_mode) ) type = "c"; // character special
if( S_ISFIFO(statbuf.st_mode) ) type = "f"; // pipe or FIFO
if( S_ISLNK(statbuf.st_mode) ) type = "l"; // symbolic link
if( S_ISSOCK(statbuf.st_mode) ) type = "s"; // socket
if( S_ISNWK(statbuf.st_mode) ) type = "n"; // network special
printf( "%2s ", type );
/* Print out type, permissions, and number of links. */
//printf("%10.10s", sperm (statbuf.st_mode));
if( S_IRUSR & statbuf.st_mode ) owner[0] = 'r';
if( S_IWUSR & statbuf.st_mode ) owner[1] = 'w';
if( S_IXUSR & statbuf.st_mode ) owner[2] = 'x';
if( S_IRGRP & statbuf.st_mode ) group[0] = 'r';
if( S_IWGRP & statbuf.st_mode ) group[1] = 'w';
if( S_IXGRP & statbuf.st_mode ) group[2] = 'x';
if( S_IROTH & statbuf.st_mode ) others[0] = 'r';
if( S_IWOTH & statbuf.st_mode ) others[1] = 'w';
if( S_IXOTH & statbuf.st_mode ) others[2] = 'x';
//printf( "\n%o\n", statbuf.st_mode );
printf( "%3o %s/%s/%s ", 0777 & statbuf.st_mode, owner, group, others );
printf("%4dL", statbuf.st_nlink);
/* Print out owner's name if it is found using getpwuid(). */
if ((pwd = getpwuid(statbuf.st_uid)) != NULL)
printf(" %-8.8s", pwd->pw_name);
else
printf(" %-8d", statbuf.st_uid);
/* Print out group name if it is found using getgrgid(). */
if ((grp = getgrgid(statbuf.st_gid)) != NULL)
printf(" %-8.8s", grp->gr_name);
else
printf(" %-8d", statbuf.st_gid);
/* Print size of file. */
//printf(" %9d", (int)statbuf.st_size);
i = 0;
size = (double) statbuf.st_size;
while (size >= 1024) {
size /= 1024;
i++;
}
if( 0 == (double)(size - (long) size) )
printf( "%7d %-2s", (long)size, units[i] );
else printf( "%7.2f %-2s", size, units[i] );
tm = localtime(&statbuf.st_mtime);
/* Get localized date string. */
strftime(datestring, sizeof(datestring), "%Y.%m.%d %T", tm); // nl_langinfo(D_T_FMT)
if ( 0 == strcmp(name, "\n") )
printf(" %s > %s", datestring, path);
else {
if( 0 == strcmp(type, "d") ) printf(" %s %s/", datestring, name);
else printf(" %s %s", datestring, name);
}
if( 0 == strcmp(type, "l") ) {
char buf[1+PATH_MAX];
if( -1 == readlink( path, buf, (1+PATH_MAX) ) ) {
fprintf( stderr, "printFSObjectInfo: error: can't read symbolic link %s\n", path);
if( 0 == strformat( &fbuf, "readlink() said: %s:", path ) ) { perror(fbuf); return -2; }
}
else {
lstat( buf, &statbuf ); // want errno, a symlink may point to non-existing object
if(errno == ENOENT) printf(" -> %s [!no such file!]\n", buf );
else {
printf(" -> %s\n", buf );
if ( 0 != strcmp(name, "\n") ) printFSObjectInfo( buf, "\n" );
}
}
}
else printf("\n");
return 0;
}
int main(int argc, char **argv) {
struct dirent *dp;
struct stat statbuf;
char *path = NULL; //[1+PATH_MAX];
char *fbuf = NULL;
char *pathArg = NULL;
if( argc == 1 || 0 == strlen(argv[1]) ) pathArg = ".";
else pathArg = argv[1];
if ( lstat( pathArg, &statbuf ) == -1 ) {
printf("%s: error: can't stat %s\n", argv[0], pathArg);
if( 0 == strformat( &fbuf, "stat() said: %s", pathArg ) ) perror(fbuf);
exit(2);
}
if( S_ISDIR(statbuf.st_mode) ) {
DIR *dir = opendir( pathArg );
if( NULL == dir ) {
fprintf( stderr, "%s: error: can't open %s\n", argv[0], pathArg );
if( 0 != strformat( &fbuf, "opendir() said: %s", pathArg ) ) exit(5);
perror(fbuf);
exit(4);
}
/* Loop through directory entries. */
while ( (dp = readdir(dir)) != NULL ) {
if( 0!= strformat( &path, "%s/%s", pathArg, dp->d_name ) ) continue;
printFSObjectInfo( path, dp->d_name );
}
closedir(dir);
} else printFSObjectInfo( pathArg, pathArg );
return 0;
}
In printFSObjectInfo() you have full functionality of lstat() system call, you can customize this to your wishes.
Be well.