目录
1.筛选给定时间范围内的日志
grep/sed/awk用正则去筛选日志时,如果要精确到小时、分钟、秒,则非常难以实现。
但是awk提供了mktime()函数,它可以将时间转换成epoch时间值。
root@Ubuntu:~# # 2019-11-10 03:42:40转换成epoch为1970-01-01 00:00:00
root@Ubuntu:~# awk 'BEGIN{print mktime("2023 08 05 08 44 40")}'
1691196280
借此,可以取得日志中的时间字符串部分,再将它们的年、月、日、时、分、秒都取出来,然后放入mktime()构建成对应的epoch值。因为epoch值是数值,所以可以比较大小,从而决定时间的大小。
下面strptime1()实现的是将2023-08-04-12-40-40 29T03:42:40+08:00
格式的字符串转换成epoch值,然后和which_time比较大小即可筛选出精确到秒的日志。
可以利用patsplit来取时间中的数字
root@Ubuntu:~# vim demo.awk
root@Ubuntu:~# cat demo.awk
BEGIN{
#要筛选什么时间的日志,将其时间构建成epoch值
which_time = mktime("2023 08 04 22 40 29")
}
{
#取出日志的日期时间字符串部分
#match($0,"^.*\\[(.*)\\].*",arr)
#将日期时间字符串转换为epoch值
tmp_time = strptime1(arr[1])
#通过比较epoch值来比较时间大小
if(tmp_time > wgich_time){print}
}
#构建的时间字符串格式为:"2023-08-04T12:40:40+08:00"
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=srr[6]
return mktime(sprintf("%s %s %s %s %s %s",Y,M,D,H,m,S))
}
下面strptime2()实现的是将10/Nov/2023:23:53:44+08:00
格式的字符串转换成epoch值,然后和which_time比较大小即可筛选出精确到秒的日志。
root@Ubuntu:~# vim dwmo.awk
root@Ubuntu:~# cat dwmo.awk
BEGIN{
要筛选什么时间的日志,将其时间构建成epoch值
which_time = mktime("2023 08 04 11 42 40")
}
{
取出日志中的日期时间字符串部分
match($0,"^.*\\[(.*)\\].*",arr)
将日期时间字符串转换为epoch值
tmp_time = strptime2(arr[1])
通过比较epoch值来比较时间大小
if(tmp_time > which_time){
}
}
构建的时间字符串格式为:"10/Nov/2023:23:53:44+08:00"
function strptime2(str,dt_str,arr,Y,M,D,H,m,S) {
dt_str = gensub("[/:+]"," ","g",str)
dt_sr = "10 Nov 2023 23 53 44 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]
}
2.统计独立IP
? url 访问IP 访问时间 访问人
案列
a.com.cn|202.109.134.23|2015-11-20 20:34:43|guest
b.com.cn|202.109.134.23|2015-11-20 20:34:48|guest
c.com.cn|202.109.134.24|2015-11-20 20:34:48|guest
a.com.cn|202.109.134.23|2015-11-20 20:34:43|guest
a.com.cn|202.109.134.24|2015-11-20 20:34:43|guest
b.com.cn|202.109.134.25|2015-11-20 20:34:48|guest
需求
统计每个URL的独立访问IP有多少个(去重),并且要为每个URL保存一个对应的文件,得到的结果类似
代码
BEGIN{
FS="|"
}
!arr[$1,$2]++{
arr1[$1]++
}
END{
for(i in arr1) {
print i, arr1[i] >(i".txt")
}
}
root@Ubuntu:~# awk -f 1.awk demo3.txtroot@Ubuntu:~# ls -al
总计 92
drwx------ 6 root root 4096 8月 5 09:50 .
drwxr-xr-x 19 root root 4096 8月 3 17:32 ..
-rw-r--r-- 1 root root 109 8月 5 09:50 1.awk
-rw-r--r-- 1 root root 11 8月 5 09:50 a.com.cn.txt-rw-r--r-- 1 root root 25 8月 4 10:19 awk
-rw------- 1 root root 973 8月 4 17:19 .bash_history
-rw-r--r-- 1 root root 3106 10月 17 2022 .bashrc
-rw-r--r-- 1 root root 11 8月 5 09:50 b.com.cn.txtdrwx------ 2 root root 4096 8月 3 18:13 .cache
-rw-r--r-- 1 root root 11 8月 5 09:50 c.com.cn.txtdrwxr-xr-x 2 root root 4096 8月 4 17:26 .cookiecutters
-rw-r--r-- 1 root root 566 8月 4 16:17 demo1.txt
-rw-r--r-- 1 root root 250 8月 5 09:24 demo2.txt
-rw-r--r-- 1 root root 300 8月 5 09:35 demo3.txt
-rw-r--r-- 1 root root 611 8月 5 09:08 demo.awk
-rw-r--r-- 1 root root 984 8月 5 08:50 dwmo.awk
-rw------- 1 root root 20 8月 4 10:37 .lesshst
-rw-r--r-- 1 root root 161 10月 17 2022 .profile
drwx------ 5 root root 4096 8月 3 17:39 snap
drwx------ 2 root root 4096 8月 3 17:39 .ssh
-rw------- 1 root root 8280 8月 5 09:50 .viminfo
运行结果
root@Ubuntu:~# cat a.com.cn.txt
a.com.cn 2
root@Ubuntu:~# cat b.com.cn.txt
b.com.cn 2
root@Ubuntu:~# cat c.com.cn.txt
c.com.cn 1
3.根据某字段去重
去掉uid=xxx
重复的行
案例
2019-01-13_12:00_index?uid=123
2019-01-13_13:00_index?uid=123
2019-01-13_14:00_index?uid=333
2019-01-13_15:00_index?uid=9710
2019-01-14_12:00_index?uid=123
2019-01-14_13:00_index?uid=123
2019-01-15_14:00_index?uid=333
2019-01-16_15:00_index?uid=9710
首先利用uid去重,我们需要利用?进行划分,然后将uid=xxx保存在数组中,这是判断重复的依据
然后统计uid出现次数,第一次出现统计,第二次不统计
运行结果
root@Ubuntu:~# vim demo2.txt
root@Ubuntu:~# awk -F"?" '!arr[$2]++{print}' demo2.txt
2019-01-13_12:00_index?uid=123
2019-01-13_14:00_index?uid=333
2019-01-13_15:00_index?uid=9710
4.正则表达式
1)认识正则
(1)介绍
正则表达式应用广泛,在绝大多数的编程语言都可以完美应用,在Linux中,也有着极大的用处。
使用正则表达式,可以有效的筛选出需要的文本,然后结合相应的支持的工具或语言,完成任务需求。
在本篇博客中,我们使用grep/egrep来完成对正则表达式的调用
(2)正则表达式类型
正则表达式可以使用正则表达式引擎实现,正则表达式引擎是解释正则表达式模式并使用这些模式匹配文本的基础软件。
在Linux中,常用的正则表达式有:
POSIX 基本正则表达式(BRE)引擎
POSIX 扩展正则表达式(BRE)引擎
2)匹配字符
. 匹配任意单个字符,不能匹配空行
[] 匹配指定范围内的任意单个字符
[^] 取反
[:alnum:] 或 [0-9a-zA-Z]
[:alpha:] 或 [a-zA-Z]
[:upper:] 或 [A-Z]
[:lower:] 或 [a-z]
[:blank:] 空白字符(空格和制表符)
[:space:] 水平和垂直的空白字符(比[:blank:]包含的范围广)
[:cntrl:] 不可打印的控制字符(退格、删除、警铃...)
[:digit:] 十进制数字 或[0-9]
[:xdigit:]十六进制数字
[:graph:] 可打印的非空白字符
[:print:] 可打印字符
[:punct:] 标点符号
3)匹配次数
* 匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配
.* 任意前面长度的任意字符,不包括0次
\? 匹配其前面的字符0 或 1次
+ 匹配其前面的字符至少1次
{n} 匹配前面的字符n次
{m,n} 匹配前面的字符至少m 次,至多n次
{,n} 匹配前面的字符至多n次
{n,} 匹配前面的字符至少n次
4)位置锚定:定位出现的位置
^ 行首锚定,用于模式的最左侧
$ 行尾锚定,用于模式的最右侧
^PATTERN$,用于模式匹配整行
^$ 空行
^[[:space:]].*$ 空白行
< 或 \b 词首锚定,用于单词模式的左侧
> 或 \b 词尾锚定;用于单词模式的右侧
<PATTERN>
5)分组和后向引用
① 分组:() 将一个或多个字符捆绑在一起,当作一个整体进行处理
分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名方式为: \1, \2, \3, ...
② 后向引用
引用前面的分组括号中的模式所匹配字符,而非模式本身
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
\2 表示从左侧起第2个左括号以及与之匹配右括号之间的模式所匹配到的字符,以此类推
& 表示前面的分组中所有字