目录
前言
awk
1.认识awk
2.使用awk
2.1语法
2.2常用命令选项
2.3awk变量
2.3.1内置变量
2.3.2自定义变量
2.4printf命令
awk例题
前言
awk、grep、sed是linux操作文本的三大利器,合称文本三剑客,也是必须掌握的linux命令之一。三者的功能都是处理文本,但侧重点各不相同,其中属awk功能最强大,但也最复杂。grep更适合单纯的查找或匹配文本,sed更适合编辑匹配到的文本,awk更适合格式化文本,对文本进行较复杂格式处理。此篇主要讲解三剑客中的awk。
awk
1.认识awk
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
2.使用awk
2.1语法
awk [options] 'pattern { action }' file
这里'options'是指常用命令选项,可选可不选,'patten'是用于匹配文本的格式,'action'是指匹配到格式时执行的动作,'file'指的是所要处理的文件。
2.2常用命令选项
- -F fs:fs指定输入分隔符,fs可以是字符串或正则表达式
- -v var=value:赋值一个用户定义变量,将外部变量传递给awk
- -f scripfile:从脚本文件中读取awk命令
2.3awk变量
变量:内置和自定义变量,每个变量前加-v命令选项
2.3.1内置变量
- FS:输入字段分隔符,默认为空白字符
- OFS:输出字段分隔符,默认为空白字符
- RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效
- ORS:输出记录换行符,输出使用指定符号代替换行符
- NF:字段数量,共有多少字段,$NF引用最后一列,$(NF-1)引用倒数第二列
- NR:行号,后可跟多个文件,第二个文件行号继续从第一个文件最后行号开始
- FNR:各文件分别计数行号,和NR一样可跟多个文件,第二个文件行号从1开始
- FILENAME:当前文件名
- ARGC:命令行参数的个数
- ARGV:数组,保存的是命令行所给定的各参数,查看参数
2.3.2自定义变量
(1)-v var=value
① 先定义变量,后执行后动作print
[root@along ~]# awk -v name="along" -F: '{print name":"$0}' awkdemo
along:hello:world
along:linux:redhat:lalala:hahaha
along:along:love:you
② 在执行动作print后定义变量
[root@along ~]# awk -F: '{print name":"$0;name="along"}' awkdemo
:hello:world
along:linux:redhat:lalala:hahaha
along:along:love:you
(2)在 program中直接定义
可以把执行的动作放在脚本中,直接调用脚本-f
[root@along ~]# cat awk.txt
{name="along";print name,$1}
[root@along ~]# awk -F: -f awk.txt awkdemo
along hello
along linux
along along
2.4printf命令
比print更强大
2.4.1格式
(1)格式化输出
printf` `"FORMAT"``, item1,item2, ...
① 必须指定FORMAT
② 不会自动换行,需要显式给出换行控制符,\n
③ FORMAT 中需要分别为后面每个item 指定格式符
(2)格式化:与item对应
- %c:显示字符的ASCII码
- %d,%i:显示十进制数
- %e,%E:显示科学计数法数值
- %f:显示为浮点数,小数
- %g,%G:以科学计数法或浮点形式显示数值
- %s:显示字符串
- %u:无符号整数
- %%: 显示%自身
(3)修饰符:%c[/d/e/f...]之间
- #[.#]:第一个数字控制显示的宽度;第二个#号表示小数点后的精度
- -:左对齐(默认右对齐)
- +:显示熟知的正负符号
awk例题
题:筛选给定范围内的日志写出来(如筛选出2023-08-06 22:20:00之后的日志)
解题步骤:
创建一个脚本文件,进行条件筛选
BEGIN{
# 要筛选什么时间的日志,将其时间构建成epoch值
which_time = mktime("2023 08 06 22 20 00")
}{
# 取出日志中的日期时间字符串部分
match($0,"^.*\\[(.*)\\].*",arr)
# 将日期时间字符串转换为epoch值
tmp_time = strptime2(arr[1])
# 通过比较epoch值来比较时间大小
if(tmp_time > which_time){
}
}# 构建的时间字符串格式为:"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 = "10 Nov 2019 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]
}
使用awk命令, 使用-f选项,选择对应的日志文件
awk -f filter_logs.awk /var/log/apache/access.log
结果: