QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

Linux 三剑客之 awk(3):awk 数组与语法

  • 2020-02-10
  • 本文字数:4621 字

    阅读完需:约 15 分钟

Linux三剑客之awk(3):awk数组与语法

一、awk 数组

1.1 数组结构

1560825858603035163.png


people[police]=110


people[doctor]=120


[root@creditease awk]# awk 'BEGIN{word[0]="credit";word[1]="easy";print word[0],word[1]}'  credit easy  [root@creditease awk]# awk 'BEGIN{word[0]="credit";word[1]="easy";for(i in word)print word[i]}'  credit  easy  
复制代码

1.2 数组分类

索 引数组:以数字为下标


关联数组:以字符串为下标

1.3 awk 关联数组

现有如下文本,格式如下:即左边是随机字母,右边是随机数字, 即将相同的字母后面的数字加在一起,按字母的顺序输出


a  1  b  3  c  2  d  7  b  5  a  3   g  2  f  6  
复制代码


1]=a[2(a[2)然后配合 END 和 for 循环输出结果:


[root@creditease awk]# awk '{a[$1]=a[$1]+$2}END{for(i in a)print i,a[i]}' jia.txt   a 4  b 8  c 2  d 7  f 6  g 2  注意:for(i in a) 循环的顺序不是按照文本内容的顺序来处理的,排序可以在命令后加sort排序  
复制代码

1.4 awk 索引数组

以数字为下标的数组 seq 生成 1-10 的数字,要求只显示计数行


[root@creditease awk]# seq 10|awk '{a[NR]=$0}END{for(i=1;i<=NR;i+=2){print a[i]}}'  1  3  5  7  9  
复制代码


seq 生成 1-10 的数字,要求不显示文件的后 3 行


[root@creditease awk]# seq 10|awk '{a[NR]=$0}END{for(i=1;i<=NR-3;i++){print a[i]}}'  1  2  3  4  5  6  7  解析:改变i的范围即可,多用于不显示文件的后几行  
复制代码

1.5 awk 数组实战去重

a++ 和 ++a


[root@creditease awk]# awk 'BEGIN{print a++}'  0  [root@creditease awk]# awk 'BEGIN{print ++a}'  1  [root@creditease awk]# awk 'BEGIN{a=1;b=a++;print a,b}'  2 1  [root@creditease awk]# awk 'BEGIN{a=1;b=++a;print a,b}'  2 2  
注:
都是 b = a+1
b=a++ 先把 a 的值赋予b,然后 a + 1
b=++a 先执行a+1,然后把a的值赋予b
复制代码


对一下文本进行去重处理 针对第二列去重


[root@creditease awk]# cat qc.txt   2018/10/20   xiaoli     13373305025  2018/10/25   xiaowang   17712215986  2018/11/01   xiaoliu    18615517895   2018/11/12   xiaoli     13373305025  2018/11/19   xiaozhao   15512013263  2018/11/26   xiaoliu    18615517895  2018/12/01   xiaoma     16965564525  2018/12/09   xiaowang   17712215986  2018/11/24   xiaozhao   15512013263  
复制代码


解法一:  [root@creditease awk]# awk '!a[$2]++' qc.txt   2018/10/20   xiaoli     13373305025  2018/10/25   xiaowang   17712215986  2018/11/01   xiaoliu    18615517895   2018/11/19   xiaozhao   15512013263  2018/12/01   xiaoma     16965564525  解析:  !a[$3]++是模式(条件),命令也可写成awk '!  a[$3]=a[$3]+1{print $0}' qc.txt  a[$3]++ ,“++”在后,先取值后加一  !a[$3]=a[$3]+1:是先取a[$3]的值,比较“!a[$3]”是否符合条件(条件非0),后加1  注意:此方法去重后的结果显示的是文本开头开始的所有不重复的行  解法二:  [root@creditease awk]# awk '++a[$2]==1' qc.txt   2018/10/20   xiaoli     13373305025  2018/10/25   xiaowang   17712215986  2018/11/01   xiaoliu    18615517895   2018/11/19   xiaozhao   15512013263  2018/12/01   xiaoma     16965564525  解析:  ++a[$3]==1是模式(条件),也可写成a[$3]=a[$3]+1==1即只有当条件(a[$3]+1的结果)为1的时候才打印出内容  ++a[$3] ,“++”在前,先加一后取值  ++a[$3]==1:是先加1,后取a[$3]的值,比较“++a[$3]”是否符合条件(值为1)  注意:此方法去重后的结果显示的是文本开头开始的所有不重复的行  解法三:  [root@creditease awk]# awk '{a[$2]=$0}END{for(i in a){print a[i]}}' qc.txt  2018/11/12   xiaoli     13373305025  2018/11/26   xiaoliu    18615517895  2018/12/01   xiaoma     16965564525  2018/12/09   xiaowang   17712215986  2018/11/24   xiaozhao   15512013263  
解析: 注意此方法去重后的结果显示的是文本结尾开始的所有不重复的行
复制代码

1.6 awk 处理多个文件(数组、NR、FNR)

使用 awk 取 file.txt 的第一列和 file1.txt 的第二列然后重定向到一个新文件 new.txt 中


[root@creditease awk]# cat file1.txt   a b  c d  e f  g h  i j  [root@creditease awk]# cat file2.txt   1 2  3 4  5 6  7 8  9 10  [root@creditease awk]# awk 'NR==FNR{a[FNR]=$1}NR!=FNR{print a[FNR],$2}' file1.txt file2.txt   a 2  c 4  e 6  g 8  i 10  解析:NR==FNR处理的是第一个文件,NR!=FNR处理的是第二个文件.  注意:当两个文件NR(行数)不同的时候,需要把行数多的放前边.  解决方法:把行数多的文件放前边,行数少的文件放后边.  把输出的结果放入一个新文件new.txt中:  [root@creditease awk]# awk 'NR==FNR{a[FNR]=$1}NR!=FNR{print a[FNR],$2>"new.txt"}' file1.txt file2.txt   [root@creditease awk]# cat new.txt   a 2  c 4  e 6  g 8  i 10  
复制代码

1.7 awk 分析日志文件,统计访问网站的个数

[root@creditease awk]# cat url.txt   http://www.baidu.com  http://mp4.video.cn  http://www.qq.com  http://www.listeneasy.com  http://mp3.music.com  http://www.qq.com  http://www.qq.com  http://www.listeneasy.com  http://www.listeneasy.com  http://mp4.video.cn  http://mp3.music.com  http://www.baidu.com  http://www.baidu.com  http://www.baidu.com  http://www.baidu.com  [root@creditease awk]# awk -F "[/]+" '{h[$2]++}END{for(i in h) print i,h[i]}' url.txt  www.qq.com 3  www.baidu.com 5  mp4.video.cn 2  mp3.music.com 2  www.crediteasy.com 3  
复制代码

二、awk 简单语法

2.1 函数 sub gsub

替换功能


格式:sub(r, s ,目标) gsub(r, s ,目标)


[root@creditease awk]# cat sub.txt   ABC DEF AHI GKL$123  BAC DEF AHI GKL$213  CBA DEF GHI GKL$321  [root@creditease awk]# awk '{sub(/A/,"a");print $0}' sub.txt   aBC DEF AHI GKL$123  BaC DEF AHI GKL$213  CBa DEF GHI GKL$321  [root@creditease awk]# awk '{gsub(/A/,"a");print $0}' sub.txt   aBC DEF aHI GKL$123  BaC DEF aHI GKL$213  CBa DEF GHI GKL$321  注:sub只会替换行内匹配的第一次内容;相当于sed ‘s###’      gsub 会替换行内匹配的所有内容;相当于sed ‘s###g’  [root@creditease awk]# awk '{sub(/A/,"a",$1);print $0}' sub.txt   aBC DEF AHI GKL$123  BaC DEF AHI GKL$213  CBa DEF GHI GKL$321  
复制代码


练习:


0001|20081223efskjfdj|EREADFASDLKJCV  0002|20081208djfksdaa|JDKFJALSDJFsddf  0003|20081208efskjfdj|EREADFASDLKJCV  0004|20081211djfksdaa1234|JDKFJALSDJFsddf  以'|'为分隔, 现要将第二个域字母前的数字去掉,其他地方都不变, 输出为:  0001|efskjfdj|EREADFASDLKJCV  0002|djfksdaa|JDKFJALSDJFsddf  0003|efskjfdj|EREADFASDLKJCV  0004|djfksdaa1234|JDKFJALSDJFsddf  
方法: awk -F '|' 'BEGIN{OFS="|"}{sub(/[0-9]+/,"",$2);print $0}' sub_hm.txt awk -F '|' -v OFS="|" '{sub(/[0-9]+/,"",$2);print $0}' sub_hm.txt
复制代码

2.2 if 和 slse 的用法

内容:


AA


BC


AA


CB


CC


AA


结果:


AA YES


BC NO YES


AA YES


CB NO YES


CC NO YES


AA YES


1) [root@creditease awk]# awk '{if($0~/AA/){print $0" YES"}else{print $0" NO YES"}}' ifelse.txt   AA YES  BC NO YES  AA YES  CB NO YES  CC NO YES  AA YES  解析:使用if和else,if $0匹配到AA,则打印$0 "YES",else反之打印$0 " NO YES"。  2)[root@creditease awk]# awk '$0~/AA/{print $0" YES"}$0!~/AA/{print $0" NO YES"}' ifelse.txt   AA YES  BC NO YES  AA YES  CB NO YES  CC NO YES  AA YES  解析:使用正则匹配,当$0匹配AA时,打印出YES,反之,打印出“NO YES”  
复制代码

2.3 next 用法

如上题,用 next 来实现


next :跳过它后边的所有代码


 [root@creditease awk]# awk '$0~/AA/{print $0" YES";next}{print $0" NO YES"}' ifelse.txt   AA YES  BC NO YES  AA YES  CB NO YES  CC NO YES  AA YES  解析:  {print $0" NO YES"}:此动作是默认执行的,当前边的$0~/AA/匹配,就会执行{print $0" YES";next}  因为action中有next,所以会跳过后边的action。  如果符合$0~/AA/则打印YES ,遇到next后,后边的动作不执行;如果不符合$0~/AA/,会执行next后边的动作;  next前边的(模式匹配),后边的就不执行,前边的不执行(模式不匹配),后边的就执行。  
复制代码

2.4 printf 不换行输出以及 next 用法

printf :打印后不换行


如下文本,如果 Description:之后为空,将其后一行内容并入此行。


Packages: Hello-1  Owner: me me me me  Other: who care?  Description:  Hello world!  Other2: don't care  想要结果:  Packages: Hello-1  Owner: me me me me  Other: who care?  Description: Hello world!  Origial-Owner: me me me me  Other2: don't care  1)[root@creditease awk]# awk '/^Desc.*:$/{printf $0}!/Desc.*:$/{print $0}' printf.txt   Packages: Hello-1  Owner: me me me me  Other: who care?  Description:Hello world!  Other2: don't care  解析:使用正则匹配,匹配到'/^Desc.*:$/,就使用printf打印(不换行),不匹配的打印出整行。  2)使用if和else实现  [root@creditease awk]# awk '{if(/Des.*:$/){printf $0}else{print $0}}' printf.txt   Packages: Hello-1  Owner: me me me me  Other: who care?  Description:Hello world!  Other2: don't care  3)使用next实现  [root@creditease awk]# awk '/Desc.*:$/{printf $0;next}{print $0}' printf.txt   Packages: Hello-1  Owner: me me me me  Other: who care?  Description:Hello world!  Other2: don't care  注:可简写成awk '/Desc.*:$/{printf $0;next}1'  printf.txt  ## 1是pattern(模式),默认action(动作)是{print $0}  
复制代码

2.5 去重后计数按要求重定向到指定文件

文本如下,要求计算出每项重复的个数,然后把重复次数大于 2 的放入 gt2.txt 文件中,把重复次数小于等于 2 的放入 le2.txt 文件中


[root@creditease files]# cat qcjs.txt   aaa  bbb  ccc  aaa  ddd  bbb  rrr  ttt  ccc  eee  ddd  rrr  bbb  rrr  bbb  [root@creditease awk]# awk '{a[$1]++}END{for(i in a){if(a[i]>2){print i,a[i]>"gt2.txt"}else{print i,a[i]>"le2.txt"}}}' qcjs.txt   [root@creditease awk]# cat gt2.txt   rrr 3  bbb 4  [root@creditease awk]# cat le2.txt   aaa 2  ccc 2  eee 1  ttt 1  ddd 2  解析:{print },或括号中打印后可直接重定向到一个新文件,文件名用双引号引起来。如: {print $1 >"xin.txt"}  
复制代码

三、awk 需注意事项

a)NR==FNR ##不能写成 NR=FNR(=在 awk 中是赋值的意思)


b)NR!=FNR ##NR 不等于 FNR


c){a=1;a[NR]} 这样会报错:同一条命令中变量和数组名不能重复 d)printf 输出的时候不换行


e){print },或括号中打印后可直接重定向到一个新文件,文件名用双引号引起来。如: {print $1 >“xin.txt”}


f)当模式(条件)是 0 的时候,后边的动作不执行,!0 的时候后边动作才执行。


本文转载自宜信技术学院网站。


原文链接:http://college.creditease.cn/detail/262


2020-02-10 21:061061

评论

发布
暂无评论
发现更多内容
Linux三剑客之awk(3):awk数组与语法_开源_秦伟_InfoQ精选文章