【问题标题】:filter dates within a text file过滤文本文件中的日期
【发布时间】:2021-08-01 08:03:46
【问题描述】:

我有一个文本文件,其中包含以下格式的数据。我们如何只打印那些日期距当前日期不到 10 天的行?

sample.txt

system system_data8 Thu Jul 29 22:36:38 2021
system system_data9 Wed Jan 24 14:43:52 2018
system system_data3 Tue Jan 23 20:25:17 2018
system system_data2 Fri Mar 09 20:37:05 2018
system system_data5 Fri Mar 09 22:02:31 2018

预期输出

system system_data8 Thu Jul 29 22:36:38 2021

我正在尝试类似下面的方法,但它不起作用。

awk -F ' ' '{printf("%s,%s,",$1,$2);"date +%F -d "$3" "$4" "$5" "$6" "$7;}' sample.txt

【问题讨论】:

    标签: shell awk


    【解决方案1】:

    GNU awk 具有时间函数:

    $ gawk -v days=10 'BEGIN {max = days*86400; now = systime()}
    NF>3 {
      mn = (index("JanFebMarAprMayJunJulAugSepOctNovDec",$(NF-3)) + 2)/3
      dt = $NF " " mn " " $(NF-2) " " gensub(/:/," ","g",$(NF-1))
      diff = now - mktime(dt)
      if (-max < diff && diff < max)
        print
    }' file
    system system_data8 Thu Jul 29 22:36:38 2021
    

    【讨论】:

      【解决方案2】:

      将 GNU awk 用于时间函数:

      $ cat tst.awk
      BEGIN {
          tgtDays = 10
          tgtSecs = tgtDays * 24 * 60 * 60
      
          endTime = strftime("%Y %m %d 12 00 00")
          endSecs = mktime(endTime,1)
      }
      {
          mthNr   = (index("JanFebMarAprMayJunJulAugSepOctNovDec",$4)+2)/3
          begTime = sprintf("%04d %02d %02d 12 00 00", $7, mthNr, $5)
          begSecs = mktime(begTime,1)
      }
      (endSecs - begSecs) < tgtSecs
      

      $ awk -f tst.awk sample.txt
      system system_data8 Thu Jul 29 22:36:38 2021
      

      请注意,在上面我们将输入数据和当前时间中的时间替换为中午,因为在确定两个日期之间的天数时,首先将时间戳转换为自纪元以来的秒数,然后除以一天中的秒数,您必须每天使用相同的时间,否则您的“天数”计算可能/将被每天的时间抛出。

      例如,查看以下尝试确定相隔 10 天的 2 个日期是否相隔不到 10 天:

      $ cat diffDatesDemo.awk
      BEGIN {
          tgtDays = 10
          tgtSecs = tgtDays * 24 * 60 * 60
      
          begTime = "2021/08/01 09:00:00"
          endTime = "2021/08/11 08:00:00"
      
          begDate = gensub(/([ :][0-9]{2}){3}$/,"",1,begTime)
          endDate = gensub(/([ :][0-9]{2}){3}$/,"",1,endTime)
      
          print "Is", begTime, "less than", tgtDays, "days before", endTime "?"
      
          ####
          print "\nWrong: Compare 2 timestamps including date plus time of day:"
          begSecs = mktime(gensub("[/:]"," ","g",begTime),1)
          endSecs = mktime(gensub("[/:]"," ","g",endTime),1)
      
          print begDate, "->", endDate, "is", ((endSecs - begSecs) < tgtSecs ? "<" : ">="), tgtDays, "days"
          ####
      
          ####
          print "\nRight: Compare 2 dates at the same time each day:"
          begSecs = mktime(gensub("[/:]"," ","g",begDate)" 12 00 00",1)
          endSecs = mktime(gensub("[/:]"," ","g",endDate)" 12 00 00",1)
      
          print begDate, "->", endDate, "is", ((endSecs - begSecs) < tgtSecs ? "<" : ">="), tgtDays, "days"
          ####
      }
      

      $ awk -f diffDatesDemo.awk
      Is 2021/08/01 09:00:00 less than 10 days before 2021/08/11 08:00:00?
      
      Wrong: Compare 2 timestamps including date plus time of day:
      2021/08/01 -> 2021/08/11 is < 10 days
      
      Right: Compare 2 dates at the same time each day:
      2021/08/01 -> 2021/08/11 is >= 10 days
      

      我还为上面的 mktime() 使用了 UTC 标志,以确保任何本地 DST 更改不会影响天数计算。

      【讨论】:

        【解决方案3】:

        如果您的 date 实用程序足够新,并且您的 shell 是 bash,您只能使用 bashdate 执行此操作:

        now=$(date +%s)
        while read sys sys_d dt; do
          sec=$(date -d "$dt" +%s)
          if (( now-sec <= 10*24*3600 )); then
            echo "$sys $sys_d $dt"
          fi
        done < sample.txt
        

        请注意,比较是在将当前日期/时间转换为 UNIX 时间戳 (date +%s) 后完成的,即自 1970 年 1 月 1 日以来的秒数。文件中的日期/时间相同。这不考虑日期/时间不规则性,例如夏令时或闰秒。因此,根据您运行此程序的时间、文件的内容以及您对 10 天 的定义,结果可能是您想要的,也可能不是您想要的。

        【讨论】:

          猜你喜欢
          • 2022-01-13
          • 1970-01-01
          • 2019-07-24
          • 1970-01-01
          • 1970-01-01
          • 2020-09-11
          • 2021-12-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多