awk(文本三剑客-行处理器+字段分割)
-
数据流的行处理工具。数据来自stdin或最后一个参数指定文件
-
-
优势:拥有自己的编程语法。支持对记录(行)和字段(分割)的处理
-
记录的概念:一行就是一条记录
-
字段的概念:一行经过分割符分割,得到多个字段。
格式
-
awk [ -F ‘re’] [‘pattern {action}’] [-f progfile] [filenames]
# BEGIN{}读取输入前执行 # END{}全部完成后执行 awk 'BEGIN{ print ">>>"} {print "ok"} END{print "----"}' /etc/hosts
指定分隔符
-
-F参数,指定分隔符re,默认为空格或tab,对分割后的每个字段都执行命令
awk -F":" '{print $1,$3}' /etc/passwd #等价于 cat /etc/passwd | awk 'BEGIN{FS=":"} {print $1,$3}' # awk读取一行输入作为"记录",赋值给变量$0 # awk对这一行分割为多个"字段",存到$1开始的变量中 # awk按照指定的格式打印,其中逗号会被映射为分隔符OFS,默认为空格 # awk接着读取下一行,重复上述流程,直到文件结束
行为
-
pattern(匹配模板):可以为正则表达式。满足条件则执行action
-
-f参数,将指定文件内容当作’pattern {action}’
变量
# 变量无需申明,直接使用。默认值为0 # 支持数组,数组的索引可以是个字符串!
内置变量
-
一般在行前命令中修改;或直接被引用输出
ARGC命令行参数个数(不包括awk的选项和awk的程序内容)。 ARGIND 当前正在处理的ARGV中的文件的索引值(同时处理多个文件时会用到)。 ARGV 命令行参数序列数组,下标从0开始。 CONVFMT 数字转换格式,和C语言中的数字输出格式化类似,默认为"%.6g"。 ENVIRON 当前系统的环境变量。 ERRNO 出错时的错误信息。 FIELDWIDTHS 以空格分隔的字段宽度,如果指定此变量,awk将会用指定的宽度替换变量FS指定的分隔符 FILENAME 当前正在处理的文件名,该变量不能在BEGIN块中使用。 FNR当前处理的记录号。 FS 字段的分隔符,默认为空格。 IGNORECASE 如果该变量设置为非0值,在进行字符串匹配时忽略大小写。 NF 记录中的字段个数。 $NF表示最后一个字段。(好用) NR 已经读出的记录数。 OFMT 数字的输出格式。 OFS 输出的字段分隔符,默认为空格。 ORS 输出的记录分隔符,默认为新行。 RS 输入记录的分隔符,默认为新行。 RSTART 被match()函数匹配的字符串的起始位置,如果没有匹配则为0(从1开始)。 RLENGTH 被match()函数匹配的字符串的长度。 SUBSEP数组中多个下标的分隔符,默认为"\034"。 # 统计一个文件的行数 cat /etc/passwd | awk '{print NR}'
内置函数
gsub(r,s) | 在整个$0中用s代替r |
---|---|
gsub(r,s,t) | 在整个t中用s替代r |
index(s,t) | 返回s中字符串t的第一位置 |
length(s) | 返回s长度 |
match(s,r) | 测试s是否包含匹配r的字符串 |
split(s,a,fs) | 在fs上将s分成序列a |
sprint(fmt,exp) | 返回经fmt格式化后的exp |
sub(r,s) | 用$0中最左边最长的子串代替s |
substr(s,p) | 返回字符串s中从p开始的后缀部分 |
substr(s,p,n) | 返回字符串s中从p开始长度为n的后缀部分 |
关系运算符
# == 字符串的完全相等需要使用 awk -F":" '$NF == "/bin/bash"' /etc/passwd # != 不相等 awk -F":" '$1 != "root"' /etc/passwd # 数字比较 <,>,<=,>= # 运算符 =-*/%^(幂) # 逻辑操作 && || #++i:从1开始加,运算在赋值 #i++: 从0开始加,赋值在运算
表达式
-
if
# {if(表达式){语句;语句;...}} # 显示管理员用户姓名 cat /etc/passwd | awk -F":" '{if($3==0) {print $1 " is administrator"}}' # 统计系统用户数量 cat /etc/passwd | awk -F":" '{if($3>=0 && $3<=1000){i++}} END{print i}'
-
for
# for(i=1;i<=2;i++) # for(i in username) # 每行打印2遍 awk '{for(i=1;i<=2;i++) {print $0}}' /etc/passwd # 先将每行的第一个值存到数组,最后再用循环打印出来。为什么打印出来是乱序的? cat /etc/passwd | awk -F":" '{username[x++]=$1} END{for(i in username) {print i,username[i]}}'
经典例子
# 统计各种shell的数量 cat /etc/passwd | awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' # 统计nginx日志出现的状态码 cat access.log | awk '{stat[$9]++} END{for(i in stat){print i,stat[i]}}' # 统计当前nginx日志中每个ip访问的数量 cat access.log | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' # 统计某一天的nginx日志中的不同ip的访问量 cat access.log |grep '28/Sep/2019' | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' # 统计nginx日志中某一天访问最多的前10个ip cat access.log |grep '28/Sep/2019' | awk '{ips[$1]++} END{for(i in ips){print i,ips[i]}}' |sort -k2 -rn | head -n 2 # sort:排序,默认升序
UV与PV统计 PV:即访问量,也就是访问您商铺的次数; UV:即访问人数,也就是有多少人来过您的商铺;需要去重 # 根据访问IP统计UV cat access.log | awk '{print $1}' |sort |uniq -c | wc -l # 根具访问ip统计PV cat access.log | awk '{print $1}' |wc -l # 或者是url 统计PV cat access.log | awk '{print $7}' |wc -l # 查询访问最频繁的URL cat access.log | awk '{print $7}'|sort | uniq -c |sort -n -k 1 -r | more # 查询访问最频繁的IP cat access.log | awk '{print $1}'|sort | uniq -c |sort -n -k 1 -r | more
本文为原创文章,转载请注明出处!