【问题标题】:How can I tell if a file is older than 30 minutes from /bin/sh?如何判断 /bin/sh 中的文件是否超过 30 分钟?
【发布时间】:2011-01-01 13:53:35
【问题描述】:

如何编写脚本来确定 /bin/sh 中的文件是否超过 30 分钟?

很遗憾,系统中不存在stat 命令。这是一个旧的 Unix 系统,http://en.wikipedia.org/wiki/Interactive_Unix

不幸的是,Perl 没有安装在系统上,客户也不想安装它,也不想安装它。

【问题讨论】:

  • 交互式 Unix,哇。如果您使用的是一个非常非标准且过时的 Unix,而不是与任何古怪版本的 shell 实用程序作斗争,那么他们最好的选择可能是使用 Perl。它应该可以编译(它有针对交互式 Unix 的规定,但您可能必须使用旧版本,因为我怀疑有人会在一段时间内完成它)并且它可能已经安装。然后它只是use File::stat; print "Older" if (time - stat($file)->mtime) > 60*30;
  • perl 很遗憾没有安装在系统上,客户也不想安装它。
  • @magol 是时候说服客户安装一些更新的软件了。向他们展示您在与过时的软件作斗争中浪费了多少时间,将其转化为您必须向他们收取的额外的 $money$,即使是完成一项简单的任务。然后请求更新。
  • 他们将在一年内更换系统。我已经准备好在 Windows 上运行的代码。但在那之前,旧系统是被管理的,他们希望在系统上尽可能少地改变,以满足其他系统的新需求
  • @magol 在这种情况下,与其升级现有软件,不如在 PATH 之外安装必要的软件。将其粘贴到正常 PATH 之外的 /usr/local/whatever 中并直接引用它,甚至只是在您的主目录中。这没有风险,而且工作量很小。

标签: linux unix sh


【解决方案1】:

以下以秒为单位为您提供文件年龄:

echo $(( `date +%s` - `stat -L --format %Y $filename` ))

这意味着这应该为超过 30 分钟的文件提供真/假值 (1/0):

echo $(( (`date +%s` - `stat -L --format %Y $filename`) > (30*60) ))

30*60 -- 一分钟60秒,不要预先计算,让CPU为你工作!

【讨论】:

  • 可读性和可维护性。这比速度更重要。
  • 对于像这样的单个命令是的,但是在大量环境中,这是一个坏习惯,具有代价高昂的缺点:浪费资源。如果您需要一个计算器来知道 7200 秒有多长,那么您就像使用 Tom-Tom 一样让自己变得愚蠢。
  • @Leo 如果计算两个数字的乘积会严重浪费您的应用程序的资源,您最好使用像 C 这样的可编译语言来解决您的问题,而不是像 sh 那样编写脚本。
  • @Leo:在大量环境中,包含幻数的代码比浪费 CPU 时间的成本要高得多。只有在少数情况下才需要进行极端的微观优化。但即使在这些情况下,最有经验的程序员也会告诉你优化的第一条规则。
  • 您在这里讨论这个微小的问题是在浪费时间和资源。写 30*60 或 1800,随你喜欢。程序员也不会真正理解问题。真的。只有在非常非常罕见的情况下,任何因 30*60 而浪费的资源才会产生任何可衡量的效果。脚踏实地。
【解决方案2】:

这是使用find 的一种方式。

if test "`find file -mmin +30`"

find 命令必须被引用以防相关文件包含空格或特殊字符。

【讨论】:

  • find 在交互式 Unix 中没有 -mmin :-(
  • 类似 test "`find "hej med dig" -mmin +30 | head -1`" 以支持文件名中的空格
  • 不幸的是,我认为它不能可靠地工作。如果 find 确实返回了一个文件名并且不构成 test 内置的可接受参数,shell 将声明它是一个错误。 @Schwern 提供的解决方案起作用的唯一原因是因为 find 返回了一个空字符串,该字符串测试评估为非零退出状态。在我看来,更好的解决方案是检查 find 是否返回了空字符串。如果 Find 没有找到文件,则 Find 没有非零退出状态。否则,可能会使用if find file -min +30。
  • @Schwern 给你。抱歉耽搁了。 cd test_dir; touch my\ file\ with\ spaces; test $(find . -type f)。 bash 4.2 上的输出是 -bash: test: <filename> unary operator expected。正如您可能已经猜到的那样,问题在于引用。如果你引用命令替换,它工作正常。
  • @gkb0986 谢谢,我在检查时错误地设置了文件时间。
【解决方案3】:

您可以通过与您创建的具有三十分钟前时间戳的参考文件进行比较来做到这一点。

首先通过输入创建您的比较文件

touch -t YYYYMMDDhhmm.ss /tmp/thirty_minutes_ago

将时间戳替换为三十分钟前的值。您可以在 Perl 中使用一个简单的单行代码自动执行此步骤。

然后使用 find 的 newer 运算符通过否定搜索运算符来匹配较旧的文件

find . \! -newer /tmp/thirty_minutes_ago -print

【讨论】:

  • 较新的作品。但是做什么\!意思是?如何在 \bin\sh 中获取 30 分钟前的时间?
  • @magol,只需减去它,例如我在 2010 年 5 月 1 日的 17:22 写这篇文章,所以“三十分钟前”文件的命令是 touch -t 201001051652.00 /tmp/thirty_minutes_ago。或者你可以使用 Perl one liner 来计算它。这 ”\!”意味着不适用于 find 命令,因此“not newer”是较旧的。 HTH
  • Interactive Unix 有没有 Tcl?它有很好的日期处理程序。
  • 消除 Perl:time_now=date +%stime_then=expr $time_now - 1800time_file=date -r <filename> +%s if $time_then -gt $time_file;然后 echo " 已超过 30 分钟"; else echo " 不到 30 分钟"; fi(未经测试,但应该足够接近。插入返回;我无法格式化评论)
  • \!只是逃避!以便将其传递给 find 命令,而不是 shell 扩展它,
【解决方案4】:

超过 30 分钟是什么意思:修改超过 30 分钟,或创建超过 30 分钟?希望是前者,因为到目前为止的答案对于这种解释是正确的。在后一种情况下,您会遇到问题,因为 unix 文件系统不跟踪文件的创建时间。 (ctime 文件属性记录了 inode 内容最后一次更改的时间,即发生了类似chmod 或chown 的情况。

如果您真的需要知道文件是否在 30 分钟前创建,您要么必须使用类似 find 的东西反复扫描文件系统的相关部分,要么使用像 linux 的 @987654321 这样依赖于平台的东西@。

【讨论】:

    【解决方案5】:

    如果您正在编写 sh 脚本,最有用的方法是使用 test 和已经提到的 stat 技巧:

    if [ `stat --format=%Y $file` -le $(( `date +%s` - 1800 )) ]; then 
        do stuff with your 30-minutes-old $file
    fi
    

    注意[ 是test 的符号链接(或其他等价物);请参阅 man test,但请记住 test 和 [ 也是 bash 内置函数,因此行为可能略有不同。 (另请注意[[ bash 复合命令)。

    【讨论】:

    • 不幸的是系统中不存在'stat':-(这是一个旧的Unix系统
    【解决方案6】:

    好的,没有统计数据和残缺的发现。以下是您的选择:

    编译GNU coreutils 以获得一个不错的发现(以及许多其他方便的命令)。您可能已经将其作为 gfind。

    如果-r 有效,也许您可​​以使用date 来获取文件修改时间?

    (`date +%s` - `date -r $file +%s`) > (30*60)
    

    或者,使用-nt 比较来选择哪个文件更新,麻烦的是制作一个mod时间在过去30分钟的文件。 touch 通常可以做到这一点,但所有可用的赌注都没有。

    touch -d '30 minutes ago' 30_minutes_ago
    if [ your_file -ot 30_minutes_ago ]; then
        ...do stuff...
    fi
    

    最后,看看 Perl 是否可用,而不是纠结于谁知道 shell 实用程序的版本。

    use File::stat;
    print "Yes" if (time - stat("yourfile")->mtime) > 60*30;
    

    【讨论】:

    • bourne 没有 -nt 、 -ot 测试,是吗?
    • "date -r" 不起作用。 “触摸-d”不起作用。但如果我给出准确的时间,我可以设定时间。但是我如何获得 30 分钟前的时间?我不能使用 Perl
    • @magol date -d '30 minutes ago' +%s 会给你 30 分钟前的时间。
    • @ghostdog74 我想我在看 bash 而不是 sh。我已经好几年没见过真正的 Bourne Shell 了。
    • date -r 在没有stat 或find 和mtime 的OpenWrt Busybox 中工作得很好。
    【解决方案7】:
    #!/usr/bin/ksh
    ## this script creates a new timer file every minute and renames all the previously created timer files and then executes whatever script you need which can now use the timer files to compare against with a find.  The script is designed to always be running on the server.  The first time the script is executed it will remove the timer files and it will take an hour to rebuild them (assuming you want 60 minutes of timer files)
    
    set -x
    
    # if the server is rebooted for any reason or this scripts stops we must rebuild the timer files from scratch
    find /yourpath/timer -type f -exec rm {} \;
    
    while [ 1 ]
    do
    COUNTER=60
    COUNTER2=60
    cd /yourpath/timer
    while [ COUNTER -gt 1 ]
    do
      COUNTER2=`expr $COUNTER - 1`
      echo COUNTER=$COUNTER
      echo COUNTER2=$COUNTER2
      if [  -f timer-minutes-$COUNTER2 ]
        then
           mv timer-minutes-$COUNTER2 timer-minutes-$COUNTER
           COUNTER=`expr $COUNTER - 1`
      else
         touch timer-minutes-$COUNTER2
      fi
    done
    
    touch timer-minutes-1
    sleep 60
    
    #this will check to see if the files have been fully updated after a server restart
    COUNT=`find . ! -newer timer-minutes-30 -type f | wc -l | awk '{print $1}'`
    if [ $COUNT -eq 1  ]
       then
         # execute whatever scripts at this point
    fi
    
    done
    

    【讨论】:

      【解决方案8】:

      对于像我这样不喜欢反勾号的人,根据@slebetman 的回答:

      echo $(( $(date +%s) - $(stat -L --format %Y $filename) > (30*60) ))
      

      【讨论】:

        【解决方案9】:
        if [[ "$(date --rfc-3339=ns -r /tmp/targetFile)" < "$(date --rfc-3339=ns --date '90 minutes ago')" ]] ; then echo "older"; fi
        

        【讨论】:

        • 欢迎来到 Stack Overflow!感谢您提供此代码 sn-p,它可能会提供一些即时帮助。一个正确的解释would greatly improve 其教育价值通过展示为什么这是一个很好的解决问题的方法,并将使它对未来有类似但不相同的问题的读者更有用。请edit您的答案添加解释,并说明适用的限制和假设。特别是这段代码中90 minutes ago的意义是什么?
        【解决方案10】:

        您可以使用 find 命令。
        例如,要在当前目录中搜索 30 分钟以上的文件:

        find . -type f -mmin +30 
        

        您可以阅读find命令HERE

        【讨论】:

        • 感谢您对我的老问题的出色回答。不幸的是,其他人在您之前给出了相同的答案。 stackoverflow.com/questions/2005021/…
        • 首先,不客气。 ;) 其次,我已经看到了答案,只是想添加更多细节和文献以进一步帮助您。干杯,米洛斯。
        【解决方案11】:

        这是我对find 的变体:

        if [ `find cache/nodes.csv -mmin +10 | egrep '.*'` ]
        

        Find 总是返回状态码0,除非它失败;但是,egrep 返回 1 是找不到匹配项。因此,如果该文件超过 10 分钟,则此组合通过。

        试试看:

        touch /tmp/foo; sleep 61; 
        find /tmp/foo -mmin +1  | egrep '.*'; echo $?
        find /tmp/foo -mmin +10 | egrep '.*'; echo $?
        

        应在文件路径后打印 0 和 1。

        我的函数使用这个:

        ##  Usage: if isFileOlderThanMinutes "$NODES_FILE_RAW" $NODES_INFO_EXPIRY; then ...
        function isFileOlderThanMinutes {
          if [ "" == "$1" ] ; then serr "isFileOlderThanMinutes() usage: isFileOlderThanMinutes <file> <minutes>"; exit; fi
          if [ "" == "$2" ] ; then serr "isFileOlderThanMinutes() usage: isFileOlderThanMinutes <file> <minutes>"; exit; fi
          ##  Does not exist -> "older"
          if [ ! -f "$1" ] ; then return 0; fi
          ##  The file older than $2 is found...
          find "$1" -mmin +$2 | egrep '.*'  > /dev/null 2>&1;
          if [ $? == 0 ] ; then return 0; fi  ## So it is older.
          return 1;  ## Else it not older.
        }
        

        【讨论】:

          【解决方案12】:

          myfile.txt的当前时间和上次修改时间之间的秒差:

          echo $(($(date +%s)-$(stat -c "%Y" myfile.txt)))
          

          您也可以使用%X 或%Z 与命令stat -c 来获取上次访问或上次状态更改之间的差异,检查是否返回0!

          %X time of last access, seconds since Epoch
          %Y time of last data modification, seconds since Epoch
          %Z time of last status change, seconds since Epoch
          

          测试:

          if [ $(($(date +%s)-$(stat -c "%Y" myfile.txt))) -lt 600 ] ; then echo younger than 600 sec ; else echo older than 600 sec ; fi
          

          【讨论】:

            猜你喜欢
            • 2014-05-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多