Сценарии оболочки Unix — поиск предыдущей даты с использованием оболочки /bin/sh

Я пишу сценарий оболочки, который извлекает все файлы в каталоге, которые последний раз изменялись x дней назад, начиная с 00:00 текущего дня.

Текущая команда find, которую я использую для этого, показана ниже, но она запустит проверку с момента запуска скрипта. Например. если скрипт был запущен в 12:00 и получил все файлы, измененные 7 дней назад или более, все файлы, которые были изменены после 12:00 7 дней назад, не будут включены в результатах поиска.

find $SEARCH_DIR -mtime +$DAYS_AGO

Я знаю, что в Bash вы можете использовать -daystart с find, чтобы решить эту проблему, но сценарий должен работать на машине IBM z/OS, которая использует / bin/sh, которая не поддерживает эту опцию.

Я видел и другие случаи, когда люди создавали файл с помощью touch и меняли отметку времени на нужную дату, используя date -d или date --date, как показано ниже, но опять же, эти параметры недоступны для меня с этой оболочкой.

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

В этом PDF-файле представлен полный список команд UNIX, поддерживаемых нашей версией IBM z/OS: http://publibfp.dhe.ibm.com/epubs/pdf/bpxza5c0.pdf

У кого-нибудь есть идеи, как побороть эту проблему? Мы будем очень признательны за любые советы.

Заранее спасибо!


person Iain Duff    schedule 26.08.2015    source источник
comment
Возможности find (или, если уж на то пошло, date) не зависят от того, какую оболочку вы используете. Возможно, вы могли бы установить GNU findutils на z/OS. (Вы также можете установить Bash, но, как указано выше, это не поможет решить эту проблему.)   -  person tripleee    schedule 26.08.2015
comment
Спасибо @tripleee, но я не думаю, что установка GNU findutils для меня вариант.   -  person Iain Duff    schedule 26.08.2015


Ответы (3)


На этой странице представлены различные POSIX-совместимых способов получить текущее количество секунд с начала эпохи. Самый простой использует awk, который использует текущее время в качестве начального значения случайного числа по умолчанию:

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

Отсюда вы можете арифметически манипулировать текущим временем:

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

Что-то вроде «3 месяца, 1 день» было бы сложно, поскольку определение месяца в GNU — это просто «тот же день, что и сегодня, но в предыдущем месяце, поэтому его нельзя легко преобразовать в фиксированное количество секунд.

person chepner    schedule 26.08.2015

Попробуйте это find . -mmin $(($(date +"%s") % (60*60*24) / 60 + 7*24*60))

пояснение:

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.
person luoluo    schedule 26.08.2015
comment
Спасибо за быстрый ответ @luoluo. К сожалению, %s не является допустимым форматом для даты в моей версии оболочки. Есть ли другой способ получить текущее время эпохи UNIX? - person Iain Duff; 26.08.2015
comment
Жалость. Вы можете реализовать date %s самостоятельно, чтобы получить текущее время эпохи UNIX. - person luoluo; 26.08.2015
comment
@IainDuff Было бы полезно, если бы вы могли указать URL-адрес справочных страниц версий find и т. Д., Которые у вас есть. Например, если у вас есть perl, для date +%s вы можете сделать perl -e 'print time;' - person meuh; 26.08.2015
comment
Спасибо @meuh, теперь я связался со всеми поддерживаемыми командами UNIX в вопросе. Я думал о Perl, но он тоже не поддерживается в нашей системе. - person Iain Duff; 26.08.2015

В старые добрые времена мы выполняли простую арифметику дат, манипулируя часовым поясом. Вам нужно найти, какой у вас ТЗ, затем вы можете сместить его на 24 часа, чтобы вернуться на 1 день назад, и так далее. (Это не работает дольше 24 часов в новых системах).

Для упрощения предположим, что мы находимся в TZ=GMT0. Затем, чтобы найти файлы старше 1 дня в полночь:

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

Сообщите нам, работает ли TZ=GMT48 для переноса даты на 2 дня назад и так далее.


В вашем вопросе говорилось скрипты оболочки, но можете ли вы прибегнуть к компиляции C? Эта маленькая программа возьмет имя файла и переместит измененное время обратно на полночь предыдущего дня. Измените -1 на количество дней. Затем вы можете создать файл, «не трогать» его с помощью этой программы и использовать 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");
}
person meuh    schedule 26.08.2015
comment
Спасибо @meuh. К сожалению, он не работает дольше 24 часов (TZ=GMT48, по-видимому, рассматривается как TZ=GMT0, как дата +%Y%m%d). просто возвращает текущую дату). - person Iain Duff; 26.08.2015
comment
Если вы можете скомпилировать, я добавил небольшую прогу C, чтобы не трогать файл. - person meuh; 27.08.2015
comment
@IainDuff Может быть, это потому, что знак отсутствует: попробуйте TZ=GMT+48 date и TZ=GMT-48 date. - person Jens; 16.07.2018