【问题标题】:SED to parse apache logs between timestampSED 解析时间戳之间的 apache 日志
【发布时间】:2018-04-25 18:19:49
【问题描述】:

我正在尝试解析日志并获取时间戳之间的行。尝试了如下所示的 sed 方法,但面临正则表达式问题

日志模式:

IP - - [20/Apr/2018:14:25:37 +0000] "GET / HTTP/1.1" 301 3936 "-" "
IP - - [20/Apr/2018:14:44:08 +0000]
----------------------------------

IP- - [20/Apr/2018:20:43:46 +0000]

我需要在 4 月 20 日获取 14:2520:43 之间的界限,因为日志还包含其他日期。

试过这个:

sed -n '/\[14:25/,/\[20:43/p' *-https_access.log.1

但不工作。

【问题讨论】:

    标签: linux shell awk sed


    【解决方案1】:

    既然你提到你想要 4 月 20 日的日志,我建议像这样:

    $ sed -n '/20\/Apr\/2018:14:25/,/20\/Apr\/2018:20:43/p' *-https_access.log.1
    

    万一“20:43”出现在其他地方,这与错误匹配发生冲突的可能性很小。

    【讨论】:

    • 如果字符串20/Apr/2018:14:2520/Apr/2018:20:43 不在日志文件中,这将失败
    【解决方案2】:

    sed 不合适,因为很难比较元素(例如日期和小时)。

    使用 awk(自我评论):

    awk -F '[ []' '
      {
      # separt date and hour then rebuild the fields
      sub(/:/, " ", $5);$0=$0""
      }
    
      # print if it s the day and between the 2 hour (string compare works in this case)
      $5 ~ /20.Apr.2018/ && $6 >= "04:25" &&  $7 < "20:44"
      ' YourFile
    

    更一般地说,我们可以使用变量将日期和小时作为参数提供给 awk(这里不是目的)

    【讨论】:

      【解决方案3】:

      要使用 sed 或 awk 打印 match1match2 之间的行,您可以这样做:

      sed -n '/match1/,/match2/p' inputfile
      awk '/match1/,/match2/' inputfile
      

      在您的示例中,match120/Apr/2018:14:25match220/Apr/2018:20:43。所以这些命令中的任何一个都应该适合你:

      sed -n '/20\/Apr\/2018:14:25/,/20\/Apr\/2018:20:43/p' inputfile
      awk '/20\/Apr\/2018:14:25/,/20\/Apr\/2018:20:43/' inputfile
      

      或者使用|作为sed的分隔符来防止转义斜杠:

      sed -n '\|20/Apr/2018:14:25|,\|20/Apr/2018:20:43|p' inputfile
      

      【讨论】:

      • 仅当日期和时间在日志中时才有效。这里就是这种情况,但你应该提到它。
      【解决方案4】:

      最好的解决方案是为此使用awk。您需要做的是将时间戳转换为 unix 时间,然后进行比较。在awk 中,您可以使用mktime() 执行此操作

      mktime(datespec [, utc-flag ]): 将 datespec 转换为与 systime() 返回的格式相同的时间戳。它类似于 ISO C 中的同名函数。参数 datespec 是 YYYY MM DD HH MM SS [DST] 形式的字符串。该字符串由 六个或七个数字分别代表全年 包括世纪,从 1 到 12 的月份,从 1 开始的日期 到 31,一天中的小时从 0 到 23,分钟从 0 到 59, 秒从 0 到 60,55 和一个可选的夏令时标志。

      为了将20/Apr/2018:14:25:37 +0000 形式的时间格式转换为2018 04 20 14 25 37 +0000

      awk -v tstart="20/Apr/2018:14:25:00" -v tend = "20/Apr/2018:20:43:00" \
           'function tounix(str) {
              split(str,a,"/|:| ")
              return mktime(a[3]" "month[a[2]]" "a[1]" "a[4]" "a[5]" "a[6])
           }
           BEGIN{
             month["Jan"]="01";month["Feb"]="02";month["Mar"]="03"
             month["Apr"]="04";month["May"]="05";month["Jun"]="06"
             month["Jul"]="07";month["Aug"]="08";month["Sep"]="09"
             month["Oct"]="10";month["Nov"]="11";month["Dec"]="12"
             FS="\\[|\\]"
             t1=tounix(tstart)
             t2=tounix(tend)
           }
           { t=tounix($2) }
           (t1<=t && t<=t)' <file>
      

      这种方法是稳健的,因为它会进行独立于闰年、日/月/年交叉的真实时间比较......与提供的其他解决方案相比,这种方法也不需要存在file中的日期tstarttend

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-30
        • 2020-08-03
        • 2013-08-31
        • 1970-01-01
        • 1970-01-01
        • 2019-09-15
        • 1970-01-01
        相关资源
        最近更新 更多