Mtime or the equivalent for HP-UX

Is there a way that we can add the equivalent of "mtime +3" to HP-UX OS?
AIX has mtime that can filter older than how many days, but it is hard to put it for HP-UX.
I am trying to filter out the output with older than 3 days. Thank you so much!!

lpstat -o |grep -v bytes |sort -nkb1 | ?? mtime +3 ?? |awk {'print $1'} > cleanuplist.txt

Have you tried these older HPUX variations?

mtime -> ls -t
atime -> ls -u
ctime -> ls -c

I'm not aware of an "mtime" command, nor can I find it in these forums's AIX man pages. Are you talking of the find test -mtime ?

Hi.

On a system like:

OS, ker|rel, machine: HP-UX, B.11.11, 9000/785
Distribution        : GenericSysName [HP Release B.11.11] (see /etc/issue)

The command which mtime
produces:

no mtime in /usr/local/bin /usr/bin /etc /usr/sbin /usr/bin/X11 /sbin /home/d/drl/bin /home/d/drl/executable

and, on a system like aix 7.1.0.0
command which mtime produces:

which: 0652-141 There is no mtime in /bin /usr/bin /usr/ucb /etc ..

cheers, drl

I have tried a couple of things, but am still in the dark.

prod:/# which mtime
no mtime

lpstat -o |grep -v bytes |sort -nkb1 has to be run, so it seems a filter has to be plugged in...

The output of lpstat -o |grep -v bytes |sort -nkb1 is shown like below:

prod:/# lpstat -o |grep -v bytes |sort -nkb1
653e-8022           prod         priority 1  Feb 22 08:42 
850wb-1934          prod         priority 1  Feb 21 07:51 on 850wb
f01l-2151           prod         priority 1  Feb 21 08:17
f01l-2154           prod         priority 1  Feb 21 08:18
f01l-2159           prod         priority 1  Feb 21 08:20
f01l-2169           prod         priority 1  Feb 21 08:20
f01l-3931           prod         priority 1  Feb 21 12:06
f01l-7075           prod         priority 1  Feb 20 07:29
f01l-7079           prod         priority 1  Feb 20 07:29
f01l-7589           prod         priority 1  Feb 22 07:12
f01l-7592           prod         priority 1  Feb 22 07:13
f01l-7604           prod         priority 1  Feb 22 07:16
f01l-7627           prod         priority 1  Feb 22 07:18
f01l-7632           prod         priority 1  Feb 22 07:21
f01l-7642           prod         priority 1  Feb 22 07:22
f01l-7673           prod         priority 1  Feb 22 07:30
f01l-7675           prod         priority 1  Feb 22 07:32
f01l-7694           prod         priority 1  Feb 22 07:35
f01l-7709           prod         priority 1  Feb 22 07:38
f01l-7713           prod         priority 1  Feb 22 07:40
f01l-9315           prod         priority 1  Feb 20 13:51
f01l-9332           prod         priority 1  Feb 20 13:52
f01l-9333           prod         priority 1  Feb 20 13:53

Is there any way that 3 days filtered so that |awk {'print $1'} > prtlist can greb the ones older than 3 days?

Thank you!!

Thought this was interesting. So I wrote something. If you do not have GNU awk or gawk(supports mktime, strptime, strftime) then you have to resort to C or perl .

This C code (see example usage in the code comments) does what you asked. But there is some weirdness in the way lpstat handles older time/date formats. Don Cragun here on the Forums may have more information on that.

Plus, you may not understand how UNIX time as epoch seconds is used to compare dates and times. Please read all the comments. TLDR; is not going to help you at all.

If you have gawk you can parody a lot of the code in the C module.

There is also the problem date/time change after six months. (Don Cragun) So this code has limits.

// timetest.c - free to copy and modify per: GNU General Public License 
//   https://www.gnu.org/licenses/licenses.en.html

// to compile with gcc
//       gcc timetest.c -o timetest
// to compile with cc  (Note HP-UX default K & R compile will NOT work)
//       cc timetest.c -o timetest
//  copy timetest to where it can be seen and executed by the correct set of users Ex:
//  cp timetest /path/to/files/
//  chmod timetest and directories as needed to allow access + execute

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>


// ignore this, it is just for a quick compile on windows, some linux, too

#ifdef __CYGWIN__     
#define _XOPEN_SOURCE 
extern char *strptime( char *, const char *, struct tm *);
#endif  
             
// *************************************************************************************
// IMPORTANT NOTE:
// The current POSIX (opengroup.org) specification for lpstat does not mention the lpstat -o output 
// format for dates of events, nor does it appear to require dates to be output at all.
//
// So, as a guess, your system does what the UNIX/HP-UX command ls does with dates of varying ages:
//  "young" file ls -l output:
//     -rwxr-xr-x 1 Owner None   494 Sep 12 09:18 arr.c
//  "old" file ls -l output:
//     -rwxr-xr-x 1 Owner None  2233 Jul 28  2018 unscr.c
//
// The DATES ARE DIFFERENT:
//    hours:minutes are dropped, replaced by year.
// lpstat is free to do the same. This code will not deal with old entries.
// The changeover in date formats happens at 6 months age AFAIK.  So if you have ancient lp requests,
// they break this code.
// *****************************************************************************************


// timetest.c jmc 2/22/2019 19:17:23 MST
// *****************************************************************
// Function: check age of date string, return 0 if okay, 1 otherwise
//    assumes the year value, handles issues in brand new year
//    returns 2 on fatal error.
//
// example usage  ----------------------------------------
// /usr/bin/lpstat -o | 
//   while read data
//   do
//     /path/to/testime $data
//     status=$?
//     if [ $status -eq 2 ]; then  
//          exit 1  # fatal error,  quit shell script
//     fi       
//     if [ $status -eq 0 ]; then 
//          echo "$data" 
//     fi        
//   done
//            ---------------------------------------------
//
//  example input data="653e-8022           prod         priority 1  Feb 22 08:42" 
//  the 5th 6th  7th values: Feb 22 08:42, first assume this year (year the code was run)
//      

// items you can et by editing a few line -------------------------------------------------
// the variable:
//            allowed_secs  
// needs to be set 
//  There are 86400 seconds in one day

#define SECS_PER_DAY 86400

// so we need a number of days , change this value to what is needed, we start with 3 days:
#define DAYS_ALLOWED 3

//  the variables min_words and max_words allow you to skip over lines
//  with too few words or too many words  
//  (note it has to be one more):
//  Take the value you want, add one to it.
//  Ex: You want 13 so enter 14.
//  This is here because lpstat -o is somewhat freeform about what it writes to stdout.

#define MAX_ALLOWED_WORDS 11
#define MIN_ALLOWED_WORDS  8

// *******************************************************************

int allowed_secs=SECS_PER_DAY * DAYS_ALLOWED;  // number of epoch seconds old
int min_words=MIN_ALLOWED_WORDS;
int max_words=MAX_ALLOWED_WORDS;

void barf(const int, const char *);
int parse(char *, char *, char *, char *);
char *trim(char *);

// fatal error exit for bad data - i.e., not valid data times
void barf(const int line, const char *input)
{
	  fprintf(stderr, "Content: %s\n", (input==NULL) ? "NULL" : input);
	  fprintf(stderr, "On line %d:\n Fatal Date/time format error %s\n", line, strerror(errno));
	  exit(2);   
}

// *****************************************************
// parse takes command line data, 
// guesses a year of the event 
// figures out current epoch seconds based on guessing a year
// compare event date in epoch seconds with limit
// return 0 if all is okay, return 1 not okay, exit when we have unexpected problems
// *****************************************************

int parse(char *mon, char *day, char *HM, char *year)
{
   int tmp_yr=0;
	 struct tm tstruct;
	 struct tm *tm=&tstruct;           // tm is now the name of the struct w want to use
   char working[80]={0x0};
   time_t now=time(NULL);
   time_t limit=now - allowed_secs;  // oldest allowed epoch time we set above
   time_t then=0;                    // epoch seconds from derived date
   int use_prev_yr=(year[0]!=0);     // tells us if we are running a second time
   
   tm=localtime(&now);               //assume no error return here
   if(use_prev_yr != 0)              // first time in the function, 
  	                                 // use the current year since year is blank
         // we get here because the original guessed year put us in the future
   	     // example: run on Jan 1 2019 with December 30th 2018 actual event date
   	     // so we get epoch seconds for December 2019  - in future.  Wrong year assumed.
   	     // guess again....
   {
     tm->tm_year--;                 // use previous year, we guessed wrong the first time	     
   }
   tmp_yr=tm->tm_year + 1900;       // set variable to  guess year
   sprintf(year, "%d", tmp_yr);     // move value of guess to string
                                    // set string "working" to values from command line     
   sprintf(working, "%s %s %s %s", mon, day, HM, year);
   memset(tm, 0x0, sizeof(struct tm)); // clear tm from previous changes
   
   if (strptime(working, "%b %d %H:%M %Y", tm)==NULL)  //next get tm for guessed year/date
   {
       errno=EINVAL;
       barf(__LINE__, working);    // strptime failed
   }
   then=mktime(tm);                // get our hopefully  "older" value in seconds
   
   if (then > now)                 // correct problem with assuming we are in the 
   	                               //  same year as the entry
   {	
      if( use_prev_yr)  // should not happen, but need to block infinite recursion
      {      	  
        	errno=EINVAL;
        	barf(__LINE__, "Invalid previous year setting");
      }
      else
      {
      	 return parse(	mon, day, HM, year);  // recursion: rerun so one year will be substracted
      }
      	 
   }
   // we got here and now know 
   //                      dates were valid, as far as we know anyway, so:
   //                         then == epoch time of event
   //                      and now == current epoch time          
   //                    and limit == oldest allowed epoch time for event

   
   if( then < limit)                         // too old
   {
   	  return 1;                              // reject event
   }
   return 0;                                 // event is okay	  
}

// chop off too long values
char *trim(char *p)
{
	 if(strlen(p)>9)  // try to preserve some junk text without flooding the screen
	 	 p[9]=0x0;
	 return p;	 
}

// driver
int main(int argc, char **argv)
{
	 char year[8]={0x0};                        // year set to "empty"
	 char errline[128]={0x0};
// garbage checks -------------------------------------------

// 1. too many or too few words in a line

	if(argc < min_words || argc > max_words )  // consider this record an airball(errant text)
	  	exit(1);                               // do not print this record

// 2. no valid data because a string is too long or someone goofed
//    Month is 3, day is 2, time (HH:MM) is 5

	if(  strnlen(argv[5],6) > 3 ||
		   strnlen(argv[6],6) > 2 ||
		   strnlen(argv[7],6) > 5 )
  {                            
  	                                        // we likely have junk data, so barf
  	 sprintf(errline, "Garbage data(truncated): %s %s %s",
  	     trim(argv[5]),
  	     trim(argv[6]),
  	     trim(argv[7]) 
  	     );
  	 errno=EINVAL;
  	 barf(__LINE__, errline);     
  }   	
// end garbage checks ------------------------------------------

	// set return code to 1 or zero (possibly 2 on major error) based on hopefully good data
	// return 1 == entry too old
	// return 0 == entry okay		   		
	
	return parse( argv[5], argv[6], argv[7], year );  
}

// EOF 2/22/2019 23:09:00 MST

Hi Jim,
The lpstat utility was dropped from the POSIX standards in 2001, but many systems will still provide it as an extension. The lpstat utility was part of the old UNIX System V line printer administration utilities and its definition at that time was hindering development of the CUPS (Common UNIX Print System) tools that were evolving at that time. CUPS frequently includes a utility named lpstat , but the output it provides is not necessarily similar to the output produced by UNIX System V or BSD variants of that utility.

Although CUPS is readily available on many systems now, it has not formally been standardized and I have not been closely enough involved in its development to make any guesses at how much variation there is in the output format used by lpstat on current systems.

You are correct in nothing that ls -l output uses month, day, hour, and minute when displaying file dates that in the range from now through six months ago. Older and newer dates use month, day, and year. (Note that when listing files found on a network, it is fairly common to see a file that has a timestamp a few milliseconds in the future if the filesystem servers aren't using network time protocol synchronization to keep their clocks in sync.)

Hope this helps,
Don

You could use perl to test if file is older that 3 days like this:

$ FILE=.profile
$  perl -e 'use File::stat;  my $INODE=stat("'$FILE'"); exit((time() - $INODE->mtime) < 3600*24*3);' && echo "File $FILE is old"
File .profile is old

Or (not a big perl coder so this could probably be simplified). Print filenames on stdin, older than 3 days:

$ ls | perl -e '
  use File::stat;
  while (my $fl = <STDIN>) { 
    chomp $fl ;
    my $INODE=stat($fl); 
    if(time() - $INODE->mtime > 3600*24*3) { 
       print $fl . "\n";
    } 
  }'

Chubler_XL - yes and no.

One problem - lpstat -o reports data from the print queue acceptance time, not the mtime of a file. In other words, you could send a 10 year old file to a print queue and acceptance time would be in the last few seconds. Try it if you have an HP-UX box handy.

Perl definitely is an option, but IIRC timelocal (and some other) and other date time .pm files were not on the last HP-UX boxes I worked on ( 11i v3 (B.11.31), 2007-02-01 ) as default installed items in perl .

Adding new perl modules requires going to cpan and downloading, then creating library directories and environment variables. And then coding. No biggie. But it is a system change.

My effort was simply in C because this was just a quick effort for me. And hoping it was useful. The missing year number part was what got me interested.

2 Likes