利用awk筛选给定时间范围内的日志

时间戳
什么是时间戳?
​ 时间戳是指格林威治时间自1970年1月1日(00:00:00 GMT)至当前时间的总秒数。它也被称为Unix时间戳(Unix Timestamp)。通俗的讲,时间戳是一份能够表示一份数据在一个特定时间点已经存在的完整的可验证的数据。

查看当前的时间戳
date +%s

[root@yangxingquan httpd]# date +%s

1691465408

系统时间

​ 一般说来就是我们执行 date命令看到的时间,linux系统下所有的时间调用都是使用的这个

时间。

​ 组成部分:主要由年月日时分秒,以及时区组成

查看当前时间

[root@yangxingquan httpd]# date

2023年 08月 08日 星期二 11:28:57 CST

利用实例理解

例一

grep/sed/awk用正则去筛选日志时,如果要精确到小时、分钟、秒,则非常难以实现。

mktime()函数

但是awk提供了mktime()函数,它可以将时间转换成epoch时间值。

# 2019-11-10 03:42:40转换成epoch为1970-01-01 00:00:00

$ awk 'BEGIN{print mktime("2019 11 10 03 42 40")}'

借此,可以取得日志中的时间字符串部分,再将它们的年、月、日、时、分、秒都取出来,然后放入mktime()构建成对应的epoch值。因为epoch值是数值,所以可

以比较大小,从而决定时间的大小。

下面strptime1()实现的是将2019-11-10T03:42:40+08:00格式的字符串转换成epoch值,

然后和which_time比较大小即可筛选出精确到秒的日志。

测试:

[root@yangxingquan httpd]# awk 'BEGIN{print mktime("2019 11 10 03 42 40")}'

1573328560

可以利用patsplit来取时间中的数字

BEGIN{
 
    #要筛选什么时间的日志,将其时间构建成epoch值
 
    which_time = mktime("2023 8 7 11 05 54")
 
}
 
 
 
{
 
    #取出日志中的日期时间字符串部分
 
    match ($0, "^.*\\[(.*)\\].*" , arr)
 
 
 
    #将日期时间字符串转换为epoch值
 
    tmp_time = strptime1(arr[1])
 
 
 
    #通过比较epoch值来比较时间大小
 
    if(tmp_time > which_time){print}}
 
 
 
    #构建的时间字符串格式为:"2023-8-7T11:05:54+08:80"
 
    function strptime1 (str,arr ,Y,M,D, H, m, S) {
 
    patsplit(str,arr,"[0-9]{1,4}")
 
    Y=arr[1]
 
    M=arr[2]
 
    D=arr[3]
 
    H=arr[4]
 
    m=arr[5]
 
    S=arr[6]
 
 
 
    #通过mktime构建字符串
 
    return mktime(sprintf("%s %s %s %s %s %s",Y,M,D,H,m,S))
 
}

程序运行逻辑先定义一个筛选时间将其转化成epoch值,然后利用正则表达式取出日志中的时间字符串将其放入arr[]数组中,循环调用strptime1()函数循环判断

#patsplit:使用正则表达式来匹配字符串,将匹配成功的部分赋给对于变量,最后显示出来。

例二

BEGIN{
 
  # 要筛选什么时间的日志,将其时间构建成epoch值
 
  which_time = mktime("2023 8 7 11 05 54")
 
}
 
 
 
{
 
  # 取出日志中的日期时间字符串部分
 
  match($0,"^.*\\[(.*)\\].*",arr)
 
 
 
  # 将日期时间字符串转换为epoch值
 
  tmp_time = strptime2(arr[1])
 
 
 
  # 通过比较epoch值来比较时间大小
 
  if(tmp_time > which_time){
 
    print
 
  }
 
}
 
 
 
# 构建的时间字符串格式为:"10/Nov/2019:23:53:44+08:00"
 
function strptime2(str   ,dt_str,arr,Y,M,D,H,m,S) {
 
  dt_str = gensub("[/:+]"," ","g",str)
 
  # dt_sr = "7 Aug 2023 11 05 54 08 00"
 
  split(dt_str,arr," ")
 
  Y=arr[3]
 
  M=mon_map(arr[2])
 
  D=arr[1]
 
  H=arr[4]
 
  m=arr[5]
 
  S=arr[6]
 
  return mktime(sprintf("%s %s %s %s %s %s",Y,M,D,H,m,S))
 
}
 
 
 
function mon_map(str   ,mons){
 
  mons["Jan"]=1
 
  mons["Feb"]=2
 
  mons["Mar"]=3
 
  mons["Apr"]=4
 
  mons["May"]=5
 
  mons["Jun"]=6
 
  mons["Jul"]=7
 
  mons["Aug"]=8
 
  mons["Sep"]=9
 
  mons["Oct"]=10
 
  mons["Nov"]=11
 
  mons["Dec"]=12
 
  return mons[str]
 
}

程序运行逻辑与例1一样,只不过不同时间格式不一样需要利用gensub()函数将/:替换成空格,再用split()将函数利用空格分隔,将英文月份转换成数字即可。

 使用 awk 命令 -f 选项 从脚本文件中读取 access.log日志文件,从而进行筛选;

你可能感兴趣的:(linux,运维,服务器)