awk的学习笔记

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

本文为原创文章,转载请注明出处!