本文的使用的示例文件
~]$ cat a.txt
ID name gender age email phone
1 Bob male 28 abc@qq.com 18023394012
2 Alice female 24 def@gmail.com 18084925203
3 Tony male 21 aaa@163.com 17048792503
4 Kevin male 21 bbb@189.com 17023929033
5 Alex male 18 ccc@xyz.com 18185904230
6 Andy female 22 ddd@139.com 18923902352
7 Jerry female 25 exdsa@189.com 18785234906
8 Peter male 20 bax@qq.com 17729348758
9 Steven female 23 bc@sohu.com 15947893212
10 Bruce female 27 bcbd@139.com 13942943905
修改字段或NF产生的联动效应
1.在使用awk进行输出时,如果修改了字段的值或者修改了变量NF,那么awk在输出的时候就会重新以OFS为间隔输出每条记录。
2.OFS可以自定义设置,如果不设置则默认为空格。
3.如果先修改字段或者NF,然后才设置OFS,那么第一行就不会以新设置的OFS为间隔,而是以默认的空格为间隔
4.使用$0=$0不能导致重新划分字段
想要重建之后的所有行都生效,那么最好先设置OFS再进行重建
~]$ awk '{$1=$1;print $0}' a.txt ##这样输出其实对文件已经产生了修改,OFS从制表符变成了空格
~]$ awk '{OFS="*";$1=$1;print $0}' a.txt ##这样就会以*号为间隔重新输出每一条记录
~]$ awk '{$1=$1;OFS="*";print $0}' a.txt ##这样设置,第一行的间隔仍然是以空格为准的,因为先设置的$1=$1,
##所以已经导致了当前行的重建,因此间隔符仍然以默认的为准
~]$ awk '{OFS="*";NF=1;print $0}' a.txt ##设置NF的值为1,导致$0重建,不过输出时也只有第一列数据
##相当于先获取第一列数据作为一个整体内容,然后再输出$0就只有ID这一列数据了
~]$ awk '{OFS="*";NF-=2;print $0}' a.txt ##NF修改导致$0重建,并且只获取前(6-2)4列的数据
~]$ awk '{OFS="*";$(NF+2)=5;print $0}' a.txt ##这样会新产生两个字段,并且$(NF+2)字段的值为5,这样也会产生$0重建
示例
使用$0重建来压缩文件中的空格
~]$ echo "a b c d e " | awk '{$1=$1;print $0}'
~]$ echo "a b c d e " | awk '{$1=$1;print $0}' OFS="-"
~]$ echo "a b c d e " | awk '{OFS="";$1=$1;print $0}' #OFS可以随意设置
awk数据筛选
1.按记录筛选
2.按字段筛选
3.按正则表达式筛选
4.定址的方式筛选
5.多条件组合筛选
1.按记录筛选,可以根据NR变量来进行判断,从而筛选指定的记录号
~]$ awk 'NR==3{print $1,$2,$3}' a.txt ##这样就可以只输出第三条记录中相应的字段了
2.按字段筛选
~]$ awk 'NR==1{print $1}' a.txt ##只输出第一条记录的第一个字段
~]$ awk '($1+0)>5{print $2}' a.txt ##将$1隐性转换到整型,然后筛选$1字段大于5的记录,并且输出$2字段
## 默认情况下,如果$1为数字,那么它的类型为strnum
## 转换后就变成了number,可使用'{print(typeof($1))}'; '{print(typeof($1+0))}'
~]$ awk '$2 ~ /\<A.*x\>/{print $6}' a.txt ##筛选$2字段满足此正则表达式的记录,并且输出该记录的$6字段
## \< \>的用法用于匹配一个单独的单词(单词前后都是空白)
3.使用正则表达式匹配
~]$ awk '/Alice/{print $0}' a.txt #匹配范围为整个记录
~]$ awk '/A.*/{print $0}' a.txt #匹配包含字母A,且后面有其他内容的
~]$ awk '/A.*y/{print $0}' a.txt
~]$ awk '/A[[:alpha:]]+y/{print $0}' a.txt
~]$ awk '/\<A.*y\>/{print $0}' a.txt ##使用正则表达式最为灵活,可以根据需要灵活使用
4.定址
~]$ awk 'NR==1 || NR==3{print $1}' a.txt ##若记录数是第一或第三条记录,那么就输出该记录的$1字段
~]$ awk 'NR==1,NR==3{print $0}' a.txt ##输出前三条记录
~]$ awk 'NR==1,$6 ~ /170*/{print $0}' a.txt ##输出从第一条记录开始到$6字段以170开头的记录
5.多条件组合筛选,以上示例中很多都是多条件组合筛选的
~]$ awk '$1 > 3 && $3 ~ /female/{print $2}' a.txt
示例
筛选ifconfig命令结果中除lo网卡之外的所有网卡的ip地址:本文仅讨论awk的筛选方式,其他方式暂不讨论
方式一:
~]$ ifconfig | awk 'BEGIN{RS="^$"}{print $6}' #这个是根据^$这个特殊分隔符来获取全文内容,然后根据空格来获取字段
方式二:
~]$ ifconfig | awk '/inet / && !/127.*/{print $2}' #先筛选出ip那一行,并过滤127.0.0.1这个ip
方式三:
~]$ ifconfig | awk 'BEGIN{RS="";FS="\n"}NR==1{$0=$2;FS=" ";$0=$0;print $2}' ##通过字段重建的方式来筛选,这个有点麻烦
awk工作流程
1.解析 -v var1=value…中的变量声明
2.编译awk源代码为awk可解释的内部各式,包括-v变量
3.执行BEGIN代码段
4.根据RS来读取文件,如果没有指定文件,那么就从标准输入中读取文件,同时执行main代码段:
- 如果在文件名部分声明变量,此阶段的变量在BEGIN之后声明的,因此此变量在BEGIN段中不可用,在main段中可用
- 每读取一条记录:
(1)都将设置NR,FNR,RT,$0等变量
(2)根据FS切割每条记录的字段,并保存至$1,$2,$3…等变量中
(3)测试main代码段中的pattern部分,测试成功则执行action部分,pattern可以有多个,每个未声明action的pattern都有一个默认action,此默认action为{print $0}。
5.执行END代码段
~]$ awk 'BEGIN{print "hello"}{print $0}END{print "end"}' a.txt ##这样就会在每个记录之前输出“hello”,
## 在输出每条记录后输出出“end”,另外hello和end需要双引号包围,不然awk当做变量处理,从而输出为空行
hello
ID name gender age email phone
end
1 Bob male 28 abc@qq.com 18023394012
end
2 Alice female 24 def@gmail.com 18084925203
end
3 Tony male 21 aaa@163.com 17048792503
end
4 Kevin male 21 bbb@189.com 17023929033
end
5 Alex male 18 ccc@xyz.com 18185904230
end
6 Andy female 22 ddd@139.com 18923902352
end
7 Jerry female 25 exdsa@189.com 18785234906
end
8 Peter male 20 bax@qq.com 17729348758
end
9 Steven female 23 bc@sohu.com 15947893212
end
10 Bruce female 27 bcbd@139.com 13942943905
end