Linux Command awk 文本匹配
文章目录
Linux Command awk 文本匹配
1. 简介
2. 原理
3. 命令
3.1 awk [选项] '{编辑指令}' 文件
3.2 与管道结合
3.3 awk [选项] '[条件]{编辑指令}' 文件
3.3 awk [选项] ' BEGIN{编辑指令 } {编辑指令} END{编辑指令}' 文件
3.4 第n到末尾参数输出
3.5 多行合并一行
3.6 获取外部变量
3.6.1 获得普通外部变量
3.6.2 BEGIN 获取变量
3.6.3 获取环境变量
3.7 内建变量
3.7.1 FS 指定字段un列分隔符(Font Space)
3.7.2 OFS 指定输出字段列分隔符(Output Font space)
3.7.3 RS 指定行分隔符 默认分隔符为\n(Row Space)
3.7.4 ORS 指定输出行分隔符
3.7.5 RT 代指分隔符
3.7.6 NF 每行字段总数(Number of Font)
3.7.7 NR 当前行数(Number of Row)
4. 脚本
5. 自定义函数
6. 数组
6.1 创建数组
6.2 删除数组元素
6.3 多维数组
7. split 切割
1. 简介
awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。
awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。
awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
2. 原理
AWK 工作流程可分为三个部分:
- 读输入文件之前执行的代码段(由BEGIN关键字标识)。
- 主循环执行输入文件的代码段。
- 读输入文件之后的代码段(由END关键字标识)。
命令结构:
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
下面的流程图描述出了 AWK 的工作流程:
1、通过关键字 BEGIN 执行 BEGIN 块的内容,即 BEGIN 后花括号 {} 的内容。
2、完成 BEGIN 块的执行,开始执行body块。
3、读入有 \n 换行符分割的记录。
4、将记录按指定的域分隔符划分域,填充域,$0 则表示所有域(即一行内容),1 表 示 第 一 个 域 , 1 表示第一个域,1表示第一个域,n 表示第 n 个域。
5、依次执行各 BODY 块,pattern 部分匹配该行内容成功后,才会执行 awk-commands 的内容。
6、循环读取并执行各行直到文件结束,完成body块执行。
7、开始 END 块执行,END 块可以输出最终结果。
3. 命令
3.1 awk [选项] ‘{编辑指令}’ 文件
awk '{print $1,$2}' /etc/rc.local //输出文件的第1、2列 head -7 /etc/passwd > passwd.txt awk -F ":" '{print $1","$7}' passwd.txt //以“:”作为分隔符,,打印第1和7列 awk -F [:/] '{print $1,$10}' passwd.txt //以“:”或“/”作为分隔符,,打印第1和10列 awk -F: '{print NR,NF}' passwd.txt // 打印行数与字段数 free | awk '/Mem/{printf("RAM Usage: %.2f\n"), $3/$2*100}'| awk '{print $3}'
3.2 与管道结合
ifconfig eth0 | grep "inet" | awk '{print $2} df -hT / | tail -1 | awk '{print $6}' uname -a | awk '{print $1,$3,$12}' //输出第1、3、12字段 seq 100 | awk 'NR%7==0||NR~/7/{print}' #列出100以内整数中7的倍数或是含7的数 seq 100 | awk '$0%7==0||$0~/7/{print}' 行号与每行的实际文本值是一致的,那么根据NR或者$0行值进行判断都是可以的。输出100以内7的倍数或是包含7的数
3.3 awk [选项] ‘[条件]{编辑指令}’ 文件
awk -F: '/bash$/{print}' passwd.txt #以bash结尾 awk -F: '/^[a-d]/{print $1,$6}' passwd.txt #以a-d任意字符开头的第1和6列字段打印 awk -F: '/^a|nologin$/{print $1,$7}' passwd.txt #以a开头或nologin结尾的第1和7列字段打印 awk -F: '$6~/bin$/{print $1,$6}' passwd.txt #以bin结尾的打印第1和6列 awk -F: '$7!~/nologin$/{print $1,$7}' passwd.txt #输出其中登录Shell不以nologin结尾(对第7个字段做!~反向匹配)的用户名、登录Shell信息 awk -F: 'NR==3{print}' passwd.txt #输出第3行(行号NR等于3)的用户记录 awk -F: 'NR%2==1{print}' passwd.txt #输出奇数行(行号NR除以2余数为1)的用户记录 awk -F: 'NR<=3{print}' passwd.txt #输出前3行文本 awk -F: 'NR>=5{print}' passwd.txt #输出从第5行开始到文件末尾的所有行 awk -F: '$1=="sync"{print}' passwd.txt #输出用户名为“sync”的行 awk -F: '$1==ENVIRON["USER"]{print $1,$6,$7}' passwd.txt #输出当前用户的用户名、宿主目录、登录Shell信息 awk -F: 'NR>=3&&NR<=5{print}' passwd.txt awk -F: '(NR>=3)&&(NR<=5){print}' passwd.txt awk -F: 'NR==3||NR==5{print}' passwd.txt awk -F: '$7!~/nologin$/||$1~/^[ad]/{print}' passwd.txt #输出“登录Shell不以nologin结尾”或者“用户名以a或d开头”的文本 awk -F: '$3<3||$3%2==0{print}' passwd.txt #输出UID小于3或者UID是偶数的用户记录 awk -F: '$3>=501&&$3<=505{print}' /etc/passwd #输出UID大于501并且小于505的行 awk -F: '/^127|^192/{print}' /etc/hosts #输出/etc/hosts映射文件内以127或者192开头的记录
3.3 awk [选项] ’ BEGIN{编辑指令 } {编辑指令} END{编辑指令}’ 文件
#打印A乘于2.56的值 awk 'BEGIN{A=1024;print A*2.56}' #统计系统中使用bash作为登录Shell的用户总个数 awk 'BEGIN{x=0}/\<bash$/{x++} END{print x}' /etc/passwd #输出的内容包括三个部分:列表头、用户信息、列表尾 awk -F: 'BEGIN{print "User\tUID\tHome"} {print $1"\t"$3"\t"$6} END{print "Total "NR" lines."}' /etc/passwd #打印行数 awk -F"\t" 'BEGIN{x=0}{x+=NF}END{print x}' /etc/passwd #以统计passwd.txt文件中以“:”分隔的总字段个数,需要每处理一行时将当前行的字段数(内置变量 awk -F: 'BEGIN{x=0}{x+=NF} END{print "Total "x" fields."}' passwd.txt #统计/etc/passwd文件中UID小于或等于500的用户个数 awk -F: 'BEGIN{i=0}{if($3<=500){i++}}END{print i}' /etc/passwd #统计/etc/passwd文件中登录Shell是“/bin/bash”的用户个数 awk -F: 'BEGIN{i=0}{if($7~/bash$/){i++}}END{print i}' /etc/passwd #统计/etc/passwd文件中登录Shell不是“/bin/bash”的用户个数 awk -F: 'BEGIN{i=0}{if($7!~/bash$/){i++}}END{print i}' /etc/passwd #分别统计/etc/passwd文件中UID小于或等于500、UID大于500的用户个数 awk -F: 'BEGIN{i=0;j=0}{if($3<=500){i++}else{j++}}END{print i,j}' /etc/passwd #分别统计/etc/passwd文件中登录Shell是“/bin/bash”、 登录Shell不是“/bin/bash”的用户个数 awk -F: 'BEGIN{i=0;j=0}{if($7~/bash$/){i++}else{j++}} END{print i,j}' /etc/passwd 分别统计/etc/passwd文件中登录Shell是“/bin/bash”、“/sbin/nologin”、其他的用户个数 awk -F: 'BEGIN{i=0;j=0;k=0}{if($7~/bash$/){i++} else if($7~/nologin$/){j++}else{k++}}END{print i,j,k}' /etc/passwd #提取IP地址及访问量 awk '{ip[$1]++} END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log #用户登陆次数 who | awk '{IP[$1]++}END{for(i in IP){print i,IP[i]}}' 列出黑名单)根据此可作防火墙 awk '{IP[$1]++}END{for(i in IP){print IP[i],i}}' /var/log/httpd/access_log | awk '$1>=500{print $2}' >>ip.log #对第1)步的结果根据访问量排名 awk '{ip[$1]++} END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log | sort -nr -k 2 求最大值: awk 'BEGIN {max = 0} {if ($1+0 > max+0) max=$1} END {print "Max=", max}' test.txt Max= 118 求最小值: awk 'BEGIN {min = 65536} {if ($1+0 < min+0) min=$1} END {print "Min=", min}' test.txt Min= 9 求和: cat test.txt|awk '{sum+=$1} END {print "Sum= ", sum}' Sum= 236 求平均值: cat test.txt|awk '{sum+=$1} END {print "Avg= ", sum/NR}' Avg= 39.3333
3.4 第n到末尾参数输出
$ echo "1 2 3 4 5" | awk '{for(i=1;i<3;i++)$i="";print}' 3 4 5 $ echo "1 2 3 4 5" | awk '{$1=$2="";print}' 3 4 5 $ echo "1 2 3 4 5" | cut -d" " -f3- 3 4 5 $ echo "1 2 3 4 5" | awk '{$1=$2=""}1' 3 4 5
3.5 多行合并一行
$ cat test MD_Q9_G1_F MD_Q9_G1_Ua MD_Q9_G1_Ub MD_Q9_G1_Uc MD_Q9_G1_Uab MD_Q9_G1_Ubc MD_Q9_G1_Uca MD_Q9_G1_Ia MD_Q9_G1_Ib MD_Q9_G1_Ic MD_Q9_G1_Pa MD_Q9_G1_Pb MD_Q9_G1_Pc MD_Q9_G1_Psum MD_Q9_G1_Qa MD_Q9_G1_Qb MD_Q9_G1_Qc MD_Q9_G1_Qsum MD_Q9_G1_Sa MD_Q9_G1_Sb MD_Q9_G1_Sc MD_Q9_G1_Ssum MD_Q9_G1_PFa MD_Q9_G1_PFb MD_Q9_G1_PFc MD_Q9_G1_PF $ awk '{ORS=NR%50?",":RS}1' test MD_Q9_G1_F,MD_Q9_G1_Ua,MD_Q9_G1_Ub,MD_Q9_G1_Uc,MD_Q9_G1_Uab,MD_Q9_G1_Ubc,MD_Q9_G1_Uca,MD_Q9_G1_Ia,MD_Q9_G1_Ib,MD_Q9_G1_Ic,MD_Q9_G1_Pa,MD_Q9_G1_Pb,MD_Q9_G1_Pc,MD_Q9_G1_Psum,MD_Q9_G1_Qa,MD_Q9_G1_Qb,MD_Q9_G1_Qc,MD_Q9_G1_Qsum,MD_Q9_G1_Sa,MD_Q9_G1_Sb,MD_Q9_G1_Sc,MD_Q9_G1_Ssum,MD_Q9_G1_PFa,MD_Q9_G1_PFb,MD_Q9_G1_PFc,MD_Q9_G1_PF, $ awk 'NR%50{printf $0",";next}1' test MD_Q9_G1_F,MD_Q9_G1_Ua,MD_Q9_G1_Ub,MD_Q9_G1_Uc,MD_Q9_G1_Uab,MD_Q9_G1_Ubc,MD_Q9_G1_Uca,MD_Q9_G1_Ia,MD_Q9_G1_Ib,MD_Q9_G1_Ic,MD_Q9_G1_Pa,MD_Q9_G1_Pb,MD_Q9_G1_Pc,MD_Q9_G1_Psum,MD_Q9_G1_Qa,MD_Q9_G1_Qb,MD_Q9_G1_Qc,MD_Q9_G1_Qsum,MD_Q9_G1_Sa,MD_Q9_G1_Sb,MD_Q9_G1_Sc,MD_Q9_G1_Ssum,MD_Q9_G1_PFa,MD_Q9_G1_PFb,MD_Q9_G1_PFc,MD_Q9_G1_PF, awk '{OFS=",";ORS=NR%50?OFS:RS}1' test MD_Q9_G1_F,MD_Q9_G1_Ua,MD_Q9_G1_Ub,MD_Q9_G1_Uc,MD_Q9_G1_Uab,MD_Q9_G1_Ubc,MD_Q9_G1_Uca,MD_Q9_G1_Ia,MD_Q9_G1_Ib,MD_Q9_G1_Ic,MD_Q9_G1_Pa,MD_Q9_G1_Pb,MD_Q9_G1_Pc,MD_Q9_G1_Psum,MD_Q9_G1_Qa,MD_Q9_G1_Qb,MD_Q9_G1_Qc,MD_Q9_G1_Qsum,MD_Q9_G1_Sa,MD_Q9_G1_Sb,MD_Q9_G1_Sc,MD_Q9_G1_Ssum,MD_Q9_G1_PFa,MD_Q9_G1_PFb,MD_Q9_G1_PFc,MD_Q9_G1_PF,
3.6 获取外部变量
3.6.1 获得普通外部变量
格式:
awk '{action}' 变量名=变量值
这样传入变量,可以在action中获得值。 注意:变量名与值放到’{action}’后面。
$ test='awk code' $ echo | awk '{print test}' test="$test" awk code
3.6.2 BEGIN 获取变量
格式:
awk –v 变量名=变量值 [–v 变量2=值2 …] 'BEGIN{action}’
注意:用-v 传入变量可以在3中类型的action 中都可以获得到,但顺序在 action前面。
$ test='awk code' $ echo | awk -v test="$test" 'BEGIN{print test}' awk code $ echo | awk -v test="$test" '{print test}' awk code
errnum=$(($errnum+1)) awk -F " " -v b="$i" -v d=$errnum '{if ($1==b) $3=d}1{print $0 > "alert_list"}' alert_list
3.6.3 获取环境变量
$ awk 'BEGIN{for (i in ENVIRON) {print i"="ENVIRON[i];}}' AWKPATH=.:/usr/share/awk SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass SELINUX_LEVEL_REQUESTED= SELINUX_ROLE_REQUESTED= LANG=en_US.UTF-8 .......
只需要调用:
awk内置变量 ENVIRON
,就可以直接获得环境变量。它是一个字典数组。环境变量名 就是它的键值。
3.7 内建变量
包含:FS,NF,NR,RT,RS,ORS,OFS
3.7.1 FS 指定字段un列分隔符(Font Space)
$ echo "111|222|333" | awk '{print $1}' 111|222|333 $ echo "111|222|333" | awk 'BEGIN{FS="|"}{print $1}' 111
3.7.2 OFS 指定输出字段列分隔符(Output Font space)
$ echo "111 222 333" |awk 'BEGIN{OFS="|";}{print $1,$2,$3}' 111|222|333
3.7.3 RS 指定行分隔符 默认分隔符为\n(Row Space)
$ echo "111 222|333 444|555 666" | awk 'BEGIN{RS="|"}{print $0}' 111 222 333 444 555 666
3.7.4 ORS 指定输出行分隔符
$ awk 'BEGIN{ORS="|";}{print $0;}' test.txt 111 222|333 444|555 666
3.7.5 RT 代指分隔符
$ echo "111 222|333 444|555 666" | awk 'BEGIN{RS="|"}{print $0,RT}' 111 222 | 333 444 | 555 666 |
3.7.6 NF 每行字段总数(Number of Font)
$ cat test.txt 111 222 333 444 555 666 $ awk '{print NF}' test.txt 2 2 2 $ awk '{print $NF}' test.txt 222 444 666
3.7.7 NR 当前行数(Number of Row)
$ cat test.txt 111 222 333 444 555 666 777 $ awk '{print NR}' test.txt 1 2 3 $ awk '{print $NR}' test.txt 111 444 777