Unix shell 脚本 - 使用 /bin/sh shell 查找以前的日期

Posted

技术标签:

【中文标题】Unix shell 脚本 - 使用 /bin/sh shell 查找以前的日期【英文标题】:Unix shell scripting - Finding a previous date using /bin/sh shell 【发布时间】:2015-08-26 11:42:39 【问题描述】:

我正在编写一个 shell 脚本,它检索一个目录中的所有文件,这些文件是 x 天前最后一次修改的,从当天 00:00 开始。

我为此使用的当前查找命令如下所示,但这将从脚本运行时开始检查。例如。如果脚本在 12:00 运行并检索到所有在 7 天或更早之前修改的文件,则所有在 7 天前12:00之后修改的文件将包含在内在查找结果中。

find $SEARCH_DIR -mtime +$DAYS_AGO

我知道在 Bash 中您可以使用 -daystartfind 来克服这个问题,但是脚本需要在使用 -daystart 的 IBM z/OS 机器上运行strong>/bin/sh shell,不支持此选项。

我见过其他情况,人们使用 touch 创建文件并使用 date -ddate 将时间戳更改为所需日期 --日期 如下所示,但这些选项再次对我不开放这个shell。

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

此 PDF 显示了我们的 IBM z/OS 版本支持的 UNIX 命令的完整列表:http://publibfp.dhe.ibm.com/epubs/pdf/bpxza5c0.pdf

有人对如何克服这个问题有任何想法吗?任何建议将不胜感激。

提前致谢!

【问题讨论】:

find(或者,就此而言,date)的功能与您使用的 shell 无关。也许您可以在 z/OS 机器上安装 GNU findutils。 (您也可以安装 Bash,但如上所述,它对解决这个问题没有帮助。) 感谢@tripleee,但我不认为安装 GNU findutils 对我来说是一个选择。 【参考方案1】:

This page 显示了多种符合 POSIX 标准的方法来获取自纪元以来的当前秒数。最简单的使用awk,它使用当前时间作为默认的随机数种子:

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

从这里,您可以算术操作当前时间:

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

“3 个月,1 天”之类的东西会很棘手,因为 GNU 对一个月的定义仅仅是“与今天相同,但在前一个月,因此不能轻易将其转换为固定的秒数.

【讨论】:

【参考方案2】:

试试这个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.

【讨论】:

感谢@luoluo 的快速回复。不幸的是,在我的 shell 版本中,%s 似乎不是 date 的有效格式。还有其他方法可以获得当前的 UNIX 纪元时间吗? 可惜。你可以自己实现一个date %s来获取当前的UNIX纪元时间。 @IainDuff 如果您可以提供一个指向您所拥有的 find 等版本的手册页的 URL,这将有所帮助。例如,如果你有 perl,对于 date +%s,你可以使用 perl -e 'print time;' 感谢@meuh,我现在已链接到问题中所有受支持的 UNIX 命令。我确实考虑过 perl,但我们的系统也不支持它。【参考方案3】:

在过去的美好时光里,我们通过操纵时区进行了一些简单的日期运算。 你需要找到你的TZ是什么,然后你可以抵消它24小时回到1天, 等等。 (这在较新的系统上不能超过 24 小时)。

为了简化,假设我们在 TZ=GMT0。然后在午夜查找超过 1 天的文件:

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

让我们知道 TZ=GMT48 是否可以将日期向后移动 2 天,依此类推。


您的问题确实是 shell 脚本,但是您可以求助于编译一些 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");

【讨论】:

谢谢@meuh。不幸的是,它似乎无法超过 24 小时(TZ=GMT48 似乎被视为 TZ=GMT0,如 date +%Y%m%d 只返回当前日期)。 如果可以编译,我添加了一个小 C 程序来取消修改文件。 @IainDuff 也许是因为缺少标志:试试TZ=GMT+48 dateTZ=GMT-48 date

以上是关于Unix shell 脚本 - 使用 /bin/sh shell 查找以前的日期的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 UNIX shell 脚本并行运行一个进程多次?

Unix shell 脚本和 PLSQL

如何在Unix中为shell脚本锁定目录[重复]

如何使用 unix shell 脚本将 impala 查询输出日志转换为变量?

UNIX 什么是 Shell 脚本

Unix shell script 找出脚本文件所在的目录?