分享安排
- awk的语法和基本概念
- awk命令使用实例
- 核心总结
1. AWK简介
AWK名字源自于三位创始人( Alfred Aho,Peter Weinberger 和 Brian Kernighan ) 名字的首字符缩写,创建者将它定义为“样式扫描和处理语言”,适合文本处理和报表生成等工作。且内建了变量,函数,数组等,功能十分强大。
2. AWK命令格式与参数
2.1 命令完整格式
awk [选项参数] 'BEGIN{command1}/pattern/{command1;command2;...}END{command1}' file
AWK命令可以由三个语句块组成,分别是BEGIN语句块,END语句块,和带**模式匹配**的常见语句块,**三个部分均是可选的**。其中pattern表示AWK在数据中查找的内容,command表示匹配内容所执行的指令。 BEGIN中command表示还未读取文件的时候执行的指令,END表示读取文件之后执行的指令。
2.2 常用选项参数
选项参数 | 解释 | 备注 |
---|---|---|
-F, —field-separator | 指定文件分隔符(输入分隔符) | 可以是一个字符或正则表达式,也可以指定多个分隔符 |
-v, —asign | 赋值一个用户定义变量 | 从shell环境传入一个变量 |
-f, —file | 从脚本文件中读取awk命令 | -f scriptfile |
2.3 常用AWK内置变量
内置变量就是AWK预定义好的、内置在AWK内部的变量,而自定义变量就是用户定义的变量
变量名 | 属性 |
---|---|
$0 | 当前记录(整行) |
$1 ~ $n | 当前记录的第n个字段 |
FS | 输入字段分隔符 默认空格 |
RS | 输出记录分隔符 默认换行符 |
NF | 当前记录中的字段个数,就是有多少列 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFS | 输出字段分隔符 默认也是空格 |
ORS | 输出的记录分隔符 默认是换行 |
自定义变量的方法
方法一:-v varname=value ,变量名区分字符大小写。
方法二:在program中直接定义。
awk -F':' '{print $1,$NF}' /etc/passwd
awk -v FS=':' '{print $1,$NF}' /etc/passwd
awk -v OFS=':' '{print $1,$NF}' /etc/passwd # 还可以重新赋值其他内置变量的值
awk 'BEGIN{FS=":"}{print $1,$NF}' /etc/passwd
3. AWK命令执行过程
3.1 核心四个字
'找谁{干啥}',相当于 '条件{命令}'。
3.2 一句话概括
awk会先执行BEGIN{}语句块中的内容,然后从文件中读入一行内容,查看是否符合模式匹配,再判断是否要执行后面的动作,重复这个动作,直到读到文件的末尾,然后执行END{}语句块中的内容。
一个最简单的例子
awk的代码:
awk 'BEGIN{count=0}/root/{count+=1}END{print "含有root的行数:" count}' /etc/passwd
含有root的行数:3
类似功能python的代码:
# encoding: utf-8
count = 0 # 相当于BEGIN语句块的变量初始化.
f = open('/etc/passwd', 'r')
for line in f.readlines(): # 循环, 每读入一行执行一次相关指令.
# 在字符串中查找子串,找不到返回-1.
if line.find('root') != -1:
count += 1
print("含有root的行数:", count) # 文件读入完毕,统计结果.
4. 基本用法
4.1 显示文件内容(相当于cat)
awk '{print $0}' /etc/passwd # 显示文件内容 相当于cat 于cat的区别是awk是逐读取文件的
等效写法
awk '{print}' /etc/passwd
awk 1 /etc/passwd
awk '{print NR" "$0}' /etc/passwd # 给文件添加行号 相当于cat -n
awk 'BEGIN{OFS=" "}{print NR, $0}' /etc/passwd
awk -F: '{print $1","$4}' /etc/passwd > demo.csv # 格式化文件
等效写法
awk 'BEGIN{FS=":";OFS=","}{print $1,$4}' /etc/passwd > demo.csv
4.2 显示文件中指定行
awk 'NR==20' /etc/passwd
awk 'NR>=20 && NR<=30' /etc/passwd
等效写法
awk '(NR>=20 && NR <=30){print $0}' /etc/passwd
awk '(NR>=20 && NR <=30){print}' /etc/passwd
awk '{if (NR>=20 && NR<=30) print $0}' /etc/passwd
4.3 显示文件中匹配到的行(相当于grep)
awk '/bash/' /etc/profile # 显示文件中包含bash的行 grep 'bash' /etc/profile
awk '/^root/' /etc/passwd # 显示文件中以root开头的行
awk '/bash$/' /etc/passwd # 显示文件中以bash结尾的行
4.4 通过指定的列匹配(grep做不到)
awk -F':' '$3 == 0' /etc/passwd
awk -F':' '$3 ~ /0/' /etc/passwd
awk -F":" '$1 == "root"' /etc/passwd
awk -F":" '$NF == "/bin/bash"' /etc/passwd
awk -F: '$(NF-1) ~ /root/' /etc/passwd
4.5 统计计算相关
统计行数
awk '{sum+=1}END{print sum}' /etc/passwd # 统计文件的行数 相当于wc -l
awk '/^$/{sum+=1}END{print sum}' /etc/profile # 统计文件中的空行 相当于grep xx /etc/passwd|wc -l
awk '/root/{sum+=1}END{print sum}' /etc/passwd # 统计包含root的行数
awk '/^root/{sum+=1}END{print sum}' /etc/passwd # 统计以root开头的行数
作为计算器
awk 'BEGIN{print 1+22,1/22}' # 只作为计算器 可使用BEGIN语句 计算精度高 echo 1/22|bc
对列求和
awk 'BEGIN{sum=0}{sum=sum+$0}END{print sum}' num.txt # 计算1加到100的结果 seq 1 101 > num.txt
awk -F: '{UID_sum+=$3}END{print UID_sum}' /etc/passwd # 对文件中的列求和
4.6 实际应用(awk数组)
进入nginx日志目录 统计网站下一级目录访问次数
awk -F' ' '{print $7}' 2020-12-23-14-access.log |awk -F'[/?]' '{sum[$2]++}END{ for (i in sum) print sum[i], i }'|sort -nr
统计每个ip访问次数(计算出现的次数)
cat 2020-12-23-*|awk -F' ' '{sum[$1]++}END{ for (i in sum) print sum[i], i }'|sort -nr
统计每个ip的流量(计算总和累加)
cat 2020-12-23-*|awk -F' ' '{sum[$1]+=$10}END{ for (i in sum) print sum[i]/1024"KB", i }'|sort -nr
4.7 进阶
内置函数gsub
sub、gsub函数相当于sed命令中的替换功能,它是awk的内建函数。
sub == ‘s###’
gsub== ‘s###g’
gsub(/找什么/,”替换为什么”,对那一行或列操作)
# 最后这个参数可选
awk -F":" '{gsub(/root/,"ROOT"); print $0}' /etc/passwd
awk -F":" '{gsub(/root/,"ROOT", $(NF-1)); print $0}' /etc/passwd # 修改后的文件丢失了OFS(输出分隔符)
awk -F":" '{gsub(/root/,"ROOT", $(NF-1));OFS=":"; print $0}' /etc/passwd # 程序内重新赋值内置变量,还原OFS
sed 's#root#ROOT#g' /etc/passwd # sed的字符串替换功能
sed -i 's#root#ROOT#g' /etc/passwd # 使用-i直接修改原文件
sed -n '/root/p' /etc/passwd # 查找
sed -n 's/root/ROOT/gp' /etc/passwd # 查找并替换 -n p合用只显示修改的部分
内置函数split
split(string, array, [field separator])
切分文件的两种思想
date +%F|awk '{split($0, a, "-"); print a[1]"年"a[2]"月"a[3]"日"}' # 格式化年月日
等效写法
date +%F|awk -F'-' '{print $1"年"$2"月"$3"日" }'
示例文件:
# cat test.txt
Tom 2012-12-11 car 53000
John 2013-01-13 bike 41000
vivi 2013-01-18 car 42800
Tom 2013-01-20 car 32500
John 2013-01-28 bike 63500
awk '{split($2,a,"-");if(a[2]==01){b[$1]+=$4}}END{for(i in b)print i,b[i]}' test.txt # 计算每人1月的花费总额
等效写法
awk -F'[ -]+' '$3 ~ /01/{sum[$1]+=$NF}END{for (i in sum) print i, sum[i]}' test.txt
下面这种写法是错误的,没有把文件切分成表格
awk '$2 ~ /01/{sum[$1]+=$4}END{for (i in sum) print i, sum[i]}' test.txt
awk '$2 ~ /01/' test.txt # 全部匹配
awk '{split($2,a,"-");if (a[2]==01) print $0}' test.txt # 匹配其中4行
内置函数substr
在列中字符长度一致时,字段内适合用来截取字符串
substr(string, start_pos, [end_pos])
head -20 2020-12-23-14-access.log |awk -F' ' '{print $1,substr($4,2,11),$7}'
内置函数length
c
调用系统命令
awk调用系统命令有两种方式
- system()
- print cmd | “/bin/bash” ```shell awk -F: ‘{ print $NF| “sort| uniq -c” }’ /etc/passwd
统计每个ip的流量并倒序 cat 2020-12-23-|awk -F’ ‘ ‘{sum[$1]+=$10}END{ for (i in sum) print sum[i]/1024”KB”, i }’|sort -nr 可改写成 cat 2020-12-23-|awk -F’ ‘ ‘{sum[$1]+=$10}END{ for (i in sum) print sum[i]/1024”KB”, i | “sort -nr”}’
保存为脚本-f执行
```shell
awk '!/^#/{sum[$2]+=$3}END{for (i in sum) print i,sum[i]/(NR/8) | "sort -nr"}' res_dmon.txt
1.保存为脚本
$ cat demo.awk
#!/bin/awk -f
!/^#/ {
sum[$2] += $3
}
END {
printf "-----------------------------------------------\n"
printf "Index:%8s\n", "Power"
for (i in sum)
printf "%5s %8.2f W\n", i, sum[i]/(NR/8) | "sort -n"
}
2.-f 参数执行脚本
awk -f demo.awk res_dmon.txt
总结
- 知道AWK命名的基本操作和命令格式、参数。了解命令的省略写法(BEGIN print)。
- 了解常用的正则表达式各符号的含义。
- 了解AWK切割文件的思想,灵活使用-F选项,把文件看作一个表格。
sed命令
N命令