0

I'm writing a shell script that retrieves all files in a directory that were last modified x days ago, starting from 00:00 on the current day.

The current find command I use for this is shown below, but this will start its check from the time the script is run. E.g. if the script was run at 12:00 and retrieved all files modified 7 days ago or more, all files that were modified after 12:00 7 days ago will not be included in the find results.

find $SEARCH_DIR -mtime +$DAYS_AGO

I know that in Bash you can use -daystart with find to overcome this, but the script needs to run on an IBM z/OS machine that uses the /bin/sh shell, which doesn't support this option.

I've seen other cases where people have created a file using touch and changed the timestamp to the desired date using date -d or date --date as shown below, but again these options aren't open to me with this shell.

date -d '7 days ago'
date --date '3 months 1 day ago'

This PDF shows a complete list of the UNIX commands supported on our IBM z/OS version: http://publibfp.dhe.ibm.com/epubs/pdf/bpxza5c0.pdf

Does anyone have any ideas about how to overcome this problem? Any advice would be greatly appreciated.

Thanks in advance!

Iain Duff
  • 3
  • 3
  • The features of `find` (or, for that matter, `date`) are unrelated to which shell you use. Maybe you could install GNU findutils on the z/OS box. (You could also install Bash but as per above, it won't help for this problem.) – tripleee Aug 26 '15 at 12:18
  • Thanks @tripleee, but I don't think installing GNU findutils is an option for me though. – Iain Duff Aug 26 '15 at 14:39

3 Answers3

1

This page shows a variety of POSIX-compliant ways to get the current number of seconds since the epoch. The simplest uses awk, which uses the current time as the default random number seed:

epoch_time=$(awk 'BEGIN { srand(); print srand() }' < /dev/null)

From here, you can manipulate the current time arithmetically:

# 7 days ago
ts=$(( epoch_time - 7 * 24 * 60 * 60 ))

Something like "3 months, 1 day" would be tricky, since GNU's definition of a month is merely "same day as today, but in a previous month, so it can't easily be converted to a fixed number of seconds.

chepner
  • 497,756
  • 71
  • 530
  • 681
0

Try this find . -mmin $(($(date +"%s") % (60*60*24) / 60 + 7*24*60))

explanation:

date +"%s"  #get current unix time_stamp

$(date +"%s") % (60*60*24) / 60 #get minutes offset from day start 

$(($(date +"%s") % (60*60*24) / 60 + 7*24*60)) 
#get minutes offset from day start of 7 days ago

find . -mmin $(($(date +"%s") % (60*60*24) / 60 + 7*24*60))
#-mmin file’s data was last modified n minutes ago.
luoluo
  • 5,353
  • 3
  • 30
  • 41
  • Thanks for the quick response @luoluo. Unfortunately **%s** doesn't seem to be a valid format for **date** in my shell version. Is there another way I may be able to get the current UNIX epoch time? – Iain Duff Aug 26 '15 at 12:20
  • Pity. You can implement a `date %s` by yourself to get the current UNIX epoch time. – luoluo Aug 26 '15 at 12:37
  • @IainDuff It would help if you could provide a url towards the man pages of the versions of find and so on you have. Eg if you have perl, for `date +%s` you can do `perl -e 'print time;'` – meuh Aug 26 '15 at 13:32
  • Thanks @meuh, I've now linked to all the supported UNIX commands in the question. I did think about perl but that's not supported on our system either. – Iain Duff Aug 26 '15 at 13:46
0

In the good old days we did some simple date arithmetic by manipulating the timezone. You need to find what your TZ is, then you can offset it by 24 hours to go back 1 day, and so on. (This doesnt work beyond 24 hours on newer systems).

To simplify, assume we are in TZ=GMT0. Then to find files older than 1 day at midnight:

date=`TZ=GMT24 date +%Y%m%d`
touch -t ${date}0000 reffile
find $SEARCH_DIR ! -newer reffile  ...

Let us know if TZ=GMT48 works to move the date back 2 days and so on.


Your question did say shell scripting but can you resort to compiling some C? This little program will take a filename and move its modified time back to midnight of the day before. Change the -1 to the number of days. You can then create a file, "untouch" it with this program, and use find ... ! -newer file.

/* reset time modified to 1 day back midnight */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>

pexit(char *s){
    perror(s);
    exit(1);
}
main(int argc,char **argv){
    char *file;
    struct stat buf;
    time_t timeoff = -1L*24*60*60;  /* one day back */
    struct timeval tvp[2];
    struct tm *tmp;

    if(argc!=2)pexit("usage: file to untouch. not ");
    file = argv[1];
    if(lstat(file,&buf)<0)pexit("cannot lstat file");
    tmp = localtime(&buf.st_mtime);
    timeoff -= tmp->tm_sec+(tmp->tm_min+tmp->tm_hour*60)*60; /* midnight */
    tvp[0].tv_sec = buf.st_atime;
    tvp[0].tv_usec = 0;
    tvp[1].tv_sec = buf.st_mtime + timeoff;
    tvp[1].tv_usec = 0;
    if(utimes(file, tvp)<0)pexit("cannot change time");
}
meuh
  • 11,500
  • 2
  • 29
  • 45
  • Thanks @meuh. Unfortunately it doesn't seem to work beyond 24 hours (**TZ=GMT48** seems to be treated as **TZ=GMT0**, as **date +%Y%m%d** just returns the current date). – Iain Duff Aug 26 '15 at 14:26
  • If you can compile, I added a small C prog to untouch a file. – meuh Aug 27 '15 at 12:15
  • @IainDuff Maybe that's because the sign is missing: try `TZ=GMT+48 date` and `TZ=GMT-48 date`. – Jens Jul 16 '18 at 12:13