分享安排

  1. awk的语法和基本概念
  2. awk命令使用实例
  3. 核心总结

    1. AWK简介

    AWK名字源自于三位创始人( Alfred Aho,Peter Weinberger 和 Brian Kernighan ) 名字的首字符缩写,创建者将它定义为“样式扫描和处理语言”,适合文本处理和报表生成等工作。且内建了变量,函数,数组等,功能十分强大。

2. AWK命令格式与参数

2.1 命令完整格式

  1. awk [选项参数] 'BEGIN{command1}/pattern/{command1;command2;...}END{command1}' file
  1. AWK命令可以由三个语句块组成,分别是BEGIN语句块,END语句块,和带**模式匹配**的常见语句块,**三个部分均是可选的**。其中pattern表示AWK在数据中查找的内容,command表示匹配内容所执行的指令。 BEGINcommand表示还未读取文件的时候执行的指令,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中直接定义。

  1. awk -F':' '{print $1,$NF}' /etc/passwd
  2. awk -v FS=':' '{print $1,$NF}' /etc/passwd
  3. awk -v OFS=':' '{print $1,$NF}' /etc/passwd # 还可以重新赋值其他内置变量的值
  4. awk 'BEGIN{FS=":"}{print $1,$NF}' /etc/passwd

3. AWK命令执行过程

3.1 核心四个字

  1. '找谁{干啥}',相当于 '条件{命令}'

3.2 一句话概括

  1. awk会先执行BEGIN{}语句块中的内容,然后从文件中读入一行内容,查看是否符合模式匹配,再判断是否要执行后面的动作,重复这个动作,直到读到文件的末尾,然后执行END{}语句块中的内容。

一个最简单的例子

awk的代码:

  1. awk 'BEGIN{count=0}/root/{count+=1}END{print "含有root的行数:" count}' /etc/passwd
  2. 含有root的行数:3

类似功能python的代码:

  1. # encoding: utf-8
  2. count = 0 # 相当于BEGIN语句块的变量初始化.
  3. f = open('/etc/passwd', 'r')
  4. for line in f.readlines(): # 循环, 每读入一行执行一次相关指令.
  5. # 在字符串中查找子串,找不到返回-1.
  6. if line.find('root') != -1:
  7. count += 1
  8. print("含有root的行数:", count) # 文件读入完毕,统计结果.

4. 基本用法

4.1 显示文件内容(相当于cat)

  1. awk '{print $0}' /etc/passwd # 显示文件内容 相当于cat 于cat的区别是awk是逐读取文件的
  2. 等效写法
  3. awk '{print}' /etc/passwd
  4. awk 1 /etc/passwd
  5. awk '{print NR" "$0}' /etc/passwd # 给文件添加行号 相当于cat -n
  6. awk 'BEGIN{OFS=" "}{print NR, $0}' /etc/passwd
  7. awk -F: '{print $1","$4}' /etc/passwd > demo.csv # 格式化文件
  8. 等效写法
  9. awk 'BEGIN{FS=":";OFS=","}{print $1,$4}' /etc/passwd > demo.csv

4.2 显示文件中指定行

  1. awk 'NR==20' /etc/passwd
  2. awk 'NR>=20 && NR<=30' /etc/passwd
  3. 等效写法
  4. awk '(NR>=20 && NR <=30){print $0}' /etc/passwd
  5. awk '(NR>=20 && NR <=30){print}' /etc/passwd
  6. awk '{if (NR>=20 && NR<=30) print $0}' /etc/passwd

4.3 显示文件中匹配到的行(相当于grep)

  1. awk '/bash/' /etc/profile # 显示文件中包含bash的行 grep 'bash' /etc/profile
  2. awk '/^root/' /etc/passwd # 显示文件中以root开头的行
  3. awk '/bash$/' /etc/passwd # 显示文件中以bash结尾的行

4.4 通过指定的列匹配(grep做不到)

  1. awk -F':' '$3 == 0' /etc/passwd
  2. awk -F':' '$3 ~ /0/' /etc/passwd
  3. awk -F":" '$1 == "root"' /etc/passwd
  4. awk -F":" '$NF == "/bin/bash"' /etc/passwd
  5. awk -F: '$(NF-1) ~ /root/' /etc/passwd

4.5 统计计算相关

统计行数

  1. awk '{sum+=1}END{print sum}' /etc/passwd # 统计文件的行数 相当于wc -l
  2. awk '/^$/{sum+=1}END{print sum}' /etc/profile # 统计文件中的空行 相当于grep xx /etc/passwd|wc -l
  3. awk '/root/{sum+=1}END{print sum}' /etc/passwd # 统计包含root的行数
  4. awk '/^root/{sum+=1}END{print sum}' /etc/passwd # 统计以root开头的行数

作为计算器

  1. awk 'BEGIN{print 1+22,1/22}' # 只作为计算器 可使用BEGIN语句 计算精度高 echo 1/22|bc

对列求和

  1. awk 'BEGIN{sum=0}{sum=sum+$0}END{print sum}' num.txt # 计算1加到100的结果 seq 1 101 > num.txt
  2. awk -F: '{UID_sum+=$3}END{print UID_sum}' /etc/passwd # 对文件中的列求和

4.6 实际应用(awk数组)

  1. 进入nginx日志目录 统计网站下一级目录访问次数
  2. 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
  3. 统计每个ip访问次数(计算出现的次数)
  4. cat 2020-12-23-*|awk -F' ' '{sum[$1]++}END{ for (i in sum) print sum[i], i }'|sort -nr
  5. 统计每个ip的流量(计算总和累加)
  6. 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(/找什么/,”替换为什么”,对那一行或列操作)
# 最后这个参数可选

  1. awk -F":" '{gsub(/root/,"ROOT"); print $0}' /etc/passwd
  2. awk -F":" '{gsub(/root/,"ROOT", $(NF-1)); print $0}' /etc/passwd # 修改后的文件丢失了OFS(输出分隔符)
  3. awk -F":" '{gsub(/root/,"ROOT", $(NF-1));OFS=":"; print $0}' /etc/passwd # 程序内重新赋值内置变量,还原OFS
  4. sed 's#root#ROOT#g' /etc/passwd # sed的字符串替换功能
  5. sed -i 's#root#ROOT#g' /etc/passwd # 使用-i直接修改原文件
  6. sed -n '/root/p' /etc/passwd # 查找
  7. sed -n 's/root/ROOT/gp' /etc/passwd # 查找并替换 -n p合用只显示修改的部分

内置函数split

split(string, array, [field separator])

切分文件的两种思想

  1. date +%F|awk '{split($0, a, "-"); print a[1]"年"a[2]"月"a[3]"日"}' # 格式化年月日
  2. 等效写法
  3. date +%F|awk -F'-' '{print $1"年"$2"月"$3"日" }'
  4. 示例文件:
  5. # cat test.txt
  6. Tom 2012-12-11 car 53000
  7. John 2013-01-13 bike 41000
  8. vivi 2013-01-18 car 42800
  9. Tom 2013-01-20 car 32500
  10. John 2013-01-28 bike 63500
  11. awk '{split($2,a,"-");if(a[2]==01){b[$1]+=$4}}END{for(i in b)print i,b[i]}' test.txt # 计算每人1月的花费总额
  12. 等效写法
  13. awk -F'[ -]+' '$3 ~ /01/{sum[$1]+=$NF}END{for (i in sum) print i, sum[i]}' test.txt
  14. 下面这种写法是错误的,没有把文件切分成表格
  15. awk '$2 ~ /01/{sum[$1]+=$4}END{for (i in sum) print i, sum[i]}' test.txt
  16. awk '$2 ~ /01/' test.txt # 全部匹配
  17. awk '{split($2,a,"-");if (a[2]==01) print $0}' test.txt # 匹配其中4行

内置函数substr

在列中字符长度一致时,字段内适合用来截取字符串
substr(string, start_pos, [end_pos])

  1. head -20 2020-12-23-14-access.log |awk -F' ' '{print $1,substr($4,2,11),$7}'

内置函数length

  1. 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”}’

  1. 保存为脚本-f执行
  2. ```shell
  3. awk '!/^#/{sum[$2]+=$3}END{for (i in sum) print i,sum[i]/(NR/8) | "sort -nr"}' res_dmon.txt
  4. 1.保存为脚本
  5. $ cat demo.awk
  6. #!/bin/awk -f
  7. !/^#/ {
  8. sum[$2] += $3
  9. }
  10. END {
  11. printf "-----------------------------------------------\n"
  12. printf "Index:%8s\n", "Power"
  13. for (i in sum)
  14. printf "%5s %8.2f W\n", i, sum[i]/(NR/8) | "sort -n"
  15. }
  16. 2.-f 参数执行脚本
  17. awk -f demo.awk res_dmon.txt

总结

  1. 知道AWK命名的基本操作和命令格式、参数。了解命令的省略写法(BEGIN print)。
  2. 了解常用的正则表达式各符号的含义。
  3. 了解AWK切割文件的思想,灵活使用-F选项,把文件看作一个表格。

sed命令
N命令
截屏2021-11-11 00.32.39.png