这是我参与新手入门的第2篇文章
写代码和写文章还是有共性的,可以把你的想法转化为代码/文章,好好享受思考的过程。
背景
上篇文章在讲Linux运维场景的时候,在日志分析部分有提到过awk,为了防止坑留的太久,这篇文章就来填上
在Linux上处理文本,使用awk还是很方便的,有的同学可能会觉得Python处理文本会更加方便,确实是这样,很多文本处理我也在用Python做,但是在处理做一些简单的文本处理的时候,借助管道还是很方便的
本文主要介绍一下awk的概念,并结合一些常见场景讲解一下awk的基本用法,我不能保证所有同学都会喜欢这种操作, 但是awk绝对会帮你在Linux处理文本的时候提高效率
简介
首先我们来先了解一下什么是awk, 以及awk常见的操作选项以及操作方法
什么是awk
虽然我们经常说awk命令,但实际上它是一种编程语言,主要用于Linux中按行处理文本和数据,相对于grep的查找,sed的编辑,awk更加注重于对于文本的切片处理,现在基本上Linux发行版本基本上都会内置awk程序
一句话理解:awk是一种按行切片处理文本数据的编程语言。
awk原理介绍
大体上介绍一下awk运行的一个过程(不感兴趣可跳过)
基本结构
awk脚本的基本结构是下面这样的
awk [options] 'BEGIN{ commands } pattern{ commands } END{ commands }' fileName
其中常用 options 包括:
-f progfile,--file=progfile:从文件执行
-F fs,--field-separator=fs:指定输入时的字段分割符,默认的是**空白字符(包含空格、TAB 字符)**
-v var=val,--assign=var=val:在执行代码之前的定义变量
复制代码
工作原理
- 获取option内容并执行,比如指定特定的分割符
- 执行BEGIN{commands} 语句块中的语句。这个可选的,BEGIN语句块是在开始读取行之前被执行的,比如一些变量初始化什么的。
- 从文件读取每一行,然后执行pattern{commands}语句块,它是顺序按行扫描文件,每一行都执行这段逻辑,一直到文件全部处理完。
- 当读至输入流最后的时候,也就是所有行都被读取并且执行完后,再执行END{commands} 语句块。比如一些打印分析结果可以写在这里面
内建变量
$0: 当前记录(存放着整行的内容)
1-n: 当前记录的第n个字段,字段是有上面说的分割符分割的
FS: 前面说过了,是分割符,默认是空格或者TAB
NF: 当前记录中的字段数,就是列数
NR: 已经读出的记录数,就是行号,多个文件的话,这个值会累加
FNR: 当前记录数,和NR不一样的是,这个值会是各个文件自己的行号
RS: 输入记录的分割符,默认是换行符
OFS:输出字段分隔符,默认也是空格
ORS:输出的记录分割符,默认为换行符
FILENAME: 当前输入的文件名
复制代码
常见用法
上面可能说的比较复杂,实际在我们使用的时候,尤其是进行日志分析的场景中,大部分都是shell操作,常见的格式是这样的
awk {commands} filename
复制代码
比如我们有a.txt, 内容如下
小明 汽车 男 1234
小红 火车 女 2234
小黑 飞机 男 3234
小白 自行车 男 4234
小绿 走路 男 4234
复制代码
示例1
$ awk '{print $0}' a.txt
复制代码
示例说明:
a.txt是我们处理的文本文件。前面单引号内部有一个大括号,里面就是每一行的处理动作print $0
。也就是打印文件中的每一行。
示例2
awk -F ':' '{print $1, $(NF-1)}' a.txt
复制代码
小明 男
小红 女
小黑 男
小白 男
小绿 男
复制代码
示例说明:
NF是列数,$(NF-1)就是倒数第二列,这样就是打印第一列和倒数第二列
示例3
awk -F ':' '{print NR ": " $2}' a.txt
复制代码
1: 汽车
2: 火车
3: 飞机
4: 自行车
5: 走路
复制代码
示例说明:
NR表示当前处理的是第几行,在里面要打印原字符,就用双引号括起来
还有一些函数以及条件的用法我在这儿就不一一列举了,大家可以自行查阅
使用场景
讲完了基本的用法,让我们来看一下在实际应用过程中的一些用法吧。结合场景大家可以理解的更快一些
统计
这里列举两个我自己平时用的较多的命令
统计一列数字的和
ls -l *.go *.conf *.sh | awk '{sum+=$5} END {print sum}'
统计每个用户的进程占了多少内存
ps aux | awk 'NR!=1{a[$1]+=$6;} END { for(i in a) print i ", " a[i]"KB";}'
从ifconfig命令的结果中筛选出除了lo网卡外的所有IPv4地址
ifconfig | awk '/inet / && !($2 ~ /^127/){print $2}'
日志分析
假设你有一个Nginx服务, 打印了一些access日志 access.log
日志格式:
'$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"'
复制代码
统计访问IP次数:
# awk '{a[$1]++}END{for(v in a)print v,a[v]}' access.log
复制代码
统计访问IP次数并排序取前10:
# awk '{a[$1]++}END{for(v in a)print v,a[v]|"sort -k2 -nr |head -10"}' access.log
复制代码
统计访问访问大于100次的IP:
# awk '{a[$1]++}END{for(v ina){if(a[v]>100)print v,a[v]}}' access.log
复制代码
统计访问最多的10个页面:
# awk '{a[$7]++}END{for(vin a)print v,a[v]|"sort -k1 -nr|head -n10"}' access.log
复制代码
统计每个IP访问状态码数量:
# awk '{a[$1" "$9]++}END{for(v ina)print v,a[v]}' access.log
复制代码
统计访问IP是404状态次数:
# awk '{if($9~/404/)a[$1" "$9]++}END{for(i in a)print v,a[v]}' access.log
复制代码
总结
本文主要介绍了awk的基本概念、基本用法以及两个常见的应用场景,希望大家看完这篇文章能在以后的日志分析中快速定位问题
时间关系,没列举太多应用场景,后续有时间或者我在工作中用到了特别有代表性的场景,我会更新在这篇文章
我是爱篮球、爱coding的程序员伍六
关注我,给你带来更多你想看的干货 ❤