文本三剑客之awk进阶篇

此篇主要讲解awk控制语句,捎带说明getline和NR_FNR命令的使用。其中会用到awk基础知识,若有疑惑,可点击文本三剑客之awk基础篇进行翻阅。

示例文件

以下为通篇会用到的几个示例文件:

[[email protected] awk_file]# cat file.txt
name yu shu wai
rick 80 86 90
long 68 89 78
jack 66 60 82
[[email protected] awk_file]# cat file.txt1
name yu shu wai
rick 80 86 90
long 68 89 78
jing 76 80 66
jack 66 60 82
[[email protected] awk_file]# cat rep.txt
hello 2018 01
nihao 2018 02
hello 2017 02
nihao 2017 01
hello 2018 01 aa
hello 2018 01
nihao 2017 02
nihao 2017 01

加{ }和不加的区别

[[email protected] awk_file]# awk ‘{/[0-9]+/}‘ file.txt    #不输出内容
[[email protected] awk_file]# awk ‘/[0-9]+/‘ file.txt
输出内容,相当于:
[[email protected] awk_file]# awk ‘{if(/[0-9]+/) print }‘ file.txt
rick 80 86 90
long 68 89 78
jack 66 60 82

去重

以下两种去重方法,若存在重复的行,会取最上面的一行记录(以aa进行参考):

[[email protected] awk_file]# awk ‘!a[$0]++‘ rep.txt
hello 2018 01
nihao 2018 02
hello 2017 02
nihao 2017 01
hello 2018 01 aa
nihao 2017 02
[[email protected] awk_file]# awk ‘++a[$0]==1‘ rep.txt
hello 2018 01
nihao 2018 02
hello 2017 02
nihao 2017 01
hello 2018 01 aa
nihao 2017 02

以$1和$2为基准进行去重:

[[email protected] awk_file]# awk ‘++a[$1 $2]==1‘ rep.txt
hello 2018 01
nihao 2018 02
hello 2017 02
nihao 2017 01

说明:
1)表达式!a[$0]++,当$0第一次出现时,a[$0]的值为0,此时先不进行++操作,那!a[$0]就为1,即进行输出;
2)当$0第二次出现时,a[$0]会先进行++操作,即a[$0]++为a[$0]=a[$0]+1=1,所以!a[$0]为0,不进行输出,依次类推;
3)只要a[$0]的值非0,那么!a[$0]结果就为假,不进行输出;
4)而++a[$0]是先进行自加再引用,所以当++a[$0]==1时,即进行输出第一次出现的行。

getline命令

getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例如打开文件失败,就返回-1。

getline语法:getline var  #将get到的行赋值给变量var 

awk getline从整体上来说,用法说明:
? 当其左右重定向符 | 或 < 时:getline作用于当前文件,读入当前文件的第一行给其后跟的变量var或$0(无变量),应该注意到,由于awk在处理getline之前已经读入了一行,所以getline得到的返回结果是隔行的。
? 当其左右重定向符 | 或 < 时:getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。

1)以下为getline的常见用法:
[[email protected] awk_file]# awk ‘BEGIN{"ls -l"|getline a;print a}‘
[[email protected] awk_file]# awk ‘BEGIN{"ls -l"|getline ;print }‘
total 44
[[email protected] awk_file]# awk ‘BEGIN{getline a<"file.txt" ;print a}‘
[[email protected] awk_file]# awk ‘BEGIN{getline <"file.txt" ;print }‘
name yu shu wai
PS:以上命令,因为getline只得到第一行,所以仅会打印第一行
2)打印偶数行:
[[email protected] awk_file]# seq 10 |awk ‘{getline;print}‘
[[email protected] awk_file]# seq 10 |awk ‘{getline a;print a}‘
2
4
6
8
10
PS:awk先读入第一行,接着处理getline,并通过getline将下一行赋值给a。
3)结合while使用:
[[email protected] awk_file]# seq 10 |awk ‘{while(getline)print}‘
2
3
4
5
[[email protected] awk_file]# seq 10 |awk ‘BEGIN{while(getline)print}‘
1
2
3
4
5
。。。。。。
[[email protected] awk_file]# awk ‘BEGIN{while(getline a<"file.txt")print a}‘
name yu shu wai
rick 80 86 90
long 68 89 78
jack 66 60 82
[[email protected] awk_file]# awk ‘BEGIN{while(getline a<"file.txt")b++;print b}‘
4
[[email protected] awk_file]# awk ‘BEGIN{while(getline <"file.txt")b++;print b}‘
4
[[email protected] awk_file]# awk ‘BEGIN{while("cat file.txt"|getline)b++;print b}‘
4
PS:因为while是循环语句,所以getline会得到所有行。

awk函数

内置函数

数值处理:

rand( ): 随机产生一个0到1之间的小数(保留小数点后6位的值);

字符串处理:

length([s]):返回指定字符串s的长度(字符个数),如果没有提供s,则返回$0的长度;
split(string, array [, r [, seps] ]):以r为分隔符进行切割字符串string,并将切割后的结果保存至数组array中,数组下标从0开始排序。若省略r,则默认由FS代替,即空白字符;
gsub(r, s [, t]):由正则表达式r所表示的模式,来匹配字符串t中的字符,将匹配到的所有字符替换为s。如果没有提供t,则默认为$0。相当于sed ‘s///g’;
sub(r, s [, t]):和gsub相似,将第一次由r匹配到的t中的字符替换为s。相当于sed ‘s///’;
substr(s, i [, n]):取字符串s中的从i开始到n个子串, 若省略n,则取剩余的所有s中的字符;
tolower(s):将s中的大写字母转换为小写;
toupper(s):将s中的小写字母转换为大写;

1)统计外部客户端访问服务器的IP数量:

[[email protected] ~]# netstat -tan |awk ‘/^tcp\>/{split($5,client,":");ip[client[1]]++}END{for(i in ip)print i,ip[i]}‘
192.168.3.29 1
0.0.0.0 8

2)将第二列的数字替换为00:

[[email protected] awk_file]# awk ‘gsub(/[0-9]+/,"00",$2)‘ file.txt
rick 00 86 90
long 00 89 78
jack 00 60 82

自定义函数

使用function进行自定义函数,格式如下:

function fname([var]){ statements }

if-else判断语句

语法格式:{if (condition) {statements}  [else {statements}] }    #[ ]中的语句表示可选

1)打印出普通用户和系统用户

[[email protected] awk_file]# awk -F: ‘{if($3>=1000)print $1,":Common User";else print $1,":Sys User"}‘ /etc/passwd
。。。。。。
mysql :Sys User
saslauth :Sys User
dovecot :Sys User
dovenull :Sys User
tony :Common User
rick :Common User
。。。。。。。

2)统计普通用户有多少个

[[email protected] awk_file]# awk -F: ‘{if($3>=1000)user++}END{print user}‘ /etc/passwd
6

for循环语句

语法格式:{for (expr1;expr2;expr3) statements}
数组用法:{for (var in array) statement}

1)将file.txt中的内容,以行为单位,打印成一列:

[[email protected] awk_file]# awk ‘{for(i=1;i<=NF;i++)print $i}‘ file.txt
name
yu
shu
wai
rick
80
86
。。。。。。
PS :awk命令本身就是以循环的方式进行处理,所以语句中的for循环,可以看成嵌套的子循环 ,从而将每行的每个字段,按单列进行打印。

2)再将其恢复成原内容:

[[email protected] awk_file]# awk ‘{for(i=1;i<=NF;i++)printf $i" "}‘ file.txt
name yu shu wai rick 80 86 90 long 68 89 78 jack 66 60 82 [[email protected] awk_file]#
[[email protected] awk_file]# awk ‘{for(i=1;i<=NF;i++)printf $i" ";print var}‘ file.txt
或
awk ‘{for(i=1;i<=NF;i++){printf $i" "}print var}‘ file.txt
name yu shu wai
rick 80 86 90
long 68 89 78
jack 66 60 82
PS:for(i=1;i<=NF;i++){printf $i" "}为每行的一个字段间循环,处理完毕后,再执行print var;
print var表示打印一个空值,即换行。

3)打印奇数列:

[[email protected] awk_file]# awk ‘{for (i=1;i<=NF;i+=2)printf $i" ";print a}‘ file.txt
name shu
rick 86
long 89
jack 60

4)打印偶数列:

[[email protected] awk_file]# awk ‘{for (i=2;i<=NF;i+=2)printf $i" ";print a}‘ file.txt
yu wai
80 90
68 78
66 82

遍历数组

一维数组

1)统计系统中使用相同bash shell的用户的数量:

~]# awk -F: ‘{shell[$NF]++}END{for(A in shell) print A,shell[A]}‘ /etc/passwd
/bin/sync 1
/bin/bash 5
/sbin/nologin 26
/bin/tcsh 1
/sbin/halt 1
/sbin/shutdown 1

分析

shell[$NF]=shell[/bin/bash]即/bin/bash为数组shell的下标;
在awk中变量第一次引用的初始值为0,即shell[$NF]=0,所以shell[$NF]++的元素值为1;这样shell[$NF]++就可以计算出,相同bash的数量。
shell[$NF]++也可以写成++shell[$NF];
A in shell中的A表示数组shell的每一个下标的名称,如A=/bin/bash,所以print A即打印出下标的名称;
shell[A]为shell数组下标为[A]的元素值,即用户默认相同shell的数量。
netstat –tan:当前正在监听或已建立连接的TCP的连接状态。

2)统计netstat中每一种tcp连接状态出现的次数:

~]# netstat -tan |awk ‘NR>2{state[$NF]++}END{for(A in state) {print A,state[A]}}‘
或
~]# netstat -tan |awk ‘/^tcp/{state[$NF]++}END{for(A in state) {print A,state[A]}}‘
LISTEN 15
ESTABLISHED 1

3)统计外部IP分别访问web的次数:

~]# awk ‘{++count[$1]}END{for (ip in count) {printf "%-20s,%5d\n",ip,count[ip]}}‘ /var/log/httpd/access_log
192.168.115.148     ,   40
::1                 ,   25
192.168.115.1       ,  755
192.168.115.145     ,  142

二维数组

使用二维数组实现行列互换,最终要实现的结果:

name rick long jack tony
yu 80 68 66 76
shu 86 89 60 90
wai 90 78 82 66

思路分析

1)原file.txt内容所对应的数组排列(五行四列):
a[1,1]=name a[1,2]=yu a[1,3]=shu a[1,4]=wai
a[2,1]=rick a[2,2]=80 a[2,3]=86 a[2,4]=90
a[3,1]=long a[3,2]=68 a[3,3]=89 a[3,4]=78
a[4,1]=jack a[4,2]=66 a[4,3]=60 a[4,4]=82
a[5,1]=tony a[5,2]=76 a[5,3]=90 a[5,4]=66
命令实现:for(i=1;i<=NF;i++)a[NR,i]=$i
2)最终结果所对应的数组排列(四行五列):
a[1,1]=name a[2,1]=rick a[3,1]=long a[4,1]=jack a[5,1]=tony
a[1,2]=yu a[2,2]=80 a[3,2]=68 a[4,2]=66 a[5,2]=76
a[1,3]=shu a[2,3]=86 a[3,3]=89 a[4,3]=60 a[5,3]=90
a[1,4]=wai a[2,4]=90 a[3,4]=78 a[4,4]=82 a[5,4]=66

命令实现说明

for(i=1;i<=NF;i++)  # i取值:1、2、3、4
for(j=1;j<=NR;j++)  # j取值:1、2、3、4、5
当i 取值1~4时,其每个值可获得5次排列组合,使用a[j,i] 可实现想要的数组(四行五列),如下:
i=1 时,a[j,i]= a[1,1] a[2,1] a[3,1] a[4,1] a[5,1]
i=2 时,a[j,i]= a[1,2] a[2,2] a[3,2] a[4,2] a[5,2]
i=3 时,a[j,i]= a[1,3] a[2,3] a[3,3] a[4,3] a[5,3]
i=4 时,a[j,i]= a[1,4] a[2,4] a[3,4] a[4,4] a[5,4]

最终命令实现

[[email protected] awk_file]#
awk ‘{for(i=1;i<=NF;i++)a[NR,i]=$i}END{for(i=1;i<=NF;i++){for(j=1;j<=NR;j++){printf a[j,i]" "}print aa}}‘ file.txt
name rick long jack tony
yu 80 68 66 76
shu 86 89 60 90
wai 90 78 82 66
PS:print aa(aa为空值)目的是每输出一行内容,执行换行操作,也可以写成printf “\n”。

此处参考:https://www.cnblogs.com/wangyuebo/p/5904565.html

while循环语句

语法格式:{while (condition) {statements } }   #条件为true,开始循环;条件为false,退出循环

1)打印出每行超过4个字符的字段:

awk -F: ‘{i=1;while (i<=NF){if (length($i)>=4) {print $i};i++}}‘ /etc/passwd
awk -F: ‘{for (i=1;i<=NF;i++) {if(length($i)>4) print $i}}‘ /etc/passwd

2)将file.txt中的内容,以行为单位,打印成一列:

[[email protected] awk_file]# awk ‘{i=1;while (i<=NF){print $i;i++}}‘ file.txt
[[email protected] awk_file]# awk ‘{for(i=1;i<=NF;i++)print $i}‘ file.txt

do-while循环语句

语法:do{ statements }while(condition)   #先执行一遍statements再进行while条件判断

将行打印为一列:

[[email protected] awk_file]# awk ‘{i=1;do{print $i;i++}while(i<=NF)}‘ file.txt

next和exit

next:提前结束对本行的处理,而直接进入下一行处理;
exit:直接退出后面所有行的处理;

1)打印ID为奇数的用户:

[[email protected] awk_file]# awk -F: ‘{if($3%2==0)next;print $1,$3}‘ /etc/passwd
[[email protected] awk_file]# awk -F: ‘{if($3%2!=0)print $1,$3}‘ /etc/passwd

2)next和exit的区别,及语句中若存在条件和多个{ action } 时,是如何执行的:

[[email protected] awk_file]# cat file
5
4
3
2
1
[[email protected] awk_file]# awk ‘$1==3{printf " ## "$0}{printf " @@ "$0}{print " aa"}‘ file
 @@ 5 aa
 @@ 4 aa
 ## 3 @@ 3 aa
 @@ 2 aa
 @@ 1 aa
[[email protected] awk_file]# awk ‘$1==3{printf " ## "$0;next}{printf " @@ "$0}{print " aa"}‘ file
 @@ 5 aa
 @@ 4 aa
 ## 3 @@ 2 aa
 @@ 1 aa
[[email protected] awk_file]# awk ‘$1==3{printf " ## "$0;exit}{printf " @@ "$0}{print " aa"}‘ file
 @@ 5 aa
 @@ 4 aa
 ## 3[[email protected] awk_file]#

NR和FNR练习

1)打印file.txt的第三列和file.txt1的第一列

[[email protected] awk_file]# awk ‘1‘ file.txt file.txt1
name yu shu wai  hhh
rick 80 86 90  hhh
long 68 89 78  hhh
jack 66 60 82  hhh
name yu shu wai
rick 80 86 90
long 68 89 78
jing 76 80 66
jack 66 60 82 [[email protected] awk_file]# awk ‘{print FNR,NR}‘ file.txt file.txt1
1 1
2 2
3 3
4 4
1 5
2 6
3 7
4 8
5 9
最终命令实现:
[[email protected] awk_file]# awk ‘NR==FNR{a[NR]=$1}NR!=FNR{print $3,a[FNR]}‘ file.txt file.txt1
shu name
86 rick
89 long
80 jack
60

说明:

符合NR==FNR条件的为紧接着awk命令的文件file.txt,因为NR和FNR显示第一个文件的行数是一样的;
符合NR!=FNR条件的为第二个文件file.txt1,因为此时FNR会从1开始打印行号;
a[NR]=$1也可以写成a[FNR]=$1;
因为NR==FNR时,会把file.txt的第一列复制给a[NR]=$1(NR取值范围1-4);
在NR!=FNR的print file.txt第一列时,需用a[FNR]实现,因此时FNR的取值范围是1-5,所以会打印file.txt的第一列(FNR取值5时是空值);

2)将text1和text内容合并,并以text中的IP排序:
习题链接:http://bbs.chinaunix.net/thread-4245971-1-3.html

[[email protected] awk_file]# cat text1
173.199.5.16    15%   packet loss
202.97.34.42    10%   packet loss
202.97.50.90    10%   packet loss
202.97.82.33    0%    packet loss
4.53.116.110    26%   packet loss
4.53.210.209    22%   packet loss
4.69.149.18     6%    packet loss
4.69.149.210    26%   packet loss
[[email protected] awk_file]# cat text
202.97.82.33 中国 电信骨干网
202.97.34.42 中国 电信骨干网
202.97.50.90 中国 电信骨干网
4.53.210.209 美国
4.69.149.18 美国
4.69.149.210 美国
4.53.116.110 美国
173.199.5.16 美国
[[email protected] awk_file]# awk ‘NR==FNR{a[$1]=$0}NR!=FNR{print a[$1]}‘ text1 text
202.97.82.33    0%    packet loss
202.97.34.42    10%   packet loss
202.97.50.90    10%   packet loss
4.53.210.209    22%   packet loss
4.69.149.18     6%    packet loss
4.69.149.210    26%   packet loss
4.53.116.110    26%   packet loss
173.199.5.16    15%   packet loss

以下为命令实现的几种写法:

[[email protected] awk_file]# awk ‘NR==FNR{a[$1]=$0}NR!=FNR{$1=a[$1];print $0}‘ text1 text
或
[[email protected] awk_file]# awk ‘NR==FNR{a[$1]=$0;next}NR!=FNR{$1=a[$1];print $0}‘ text1 text
或
[[email protected] awk_file]# awk ‘NR==FNR{a[$1]=$0;next}NR!=FNR{$1=a[$1]}1‘ text1 text
或
[[email protected] awk_file]# awk ‘NR==FNR{a[$1]=$0;next}{$1=a[$1]}1‘ text1 text
202.97.82.33    0%    packet loss 中国 电信骨干网
202.97.34.42    10%   packet loss 中国 电信骨干网
202.97.50.90    10%   packet loss 中国 电信骨干网
4.53.210.209    22%   packet loss 美国
4.69.149.18     6%    packet loss 美国
4.69.149.210    26%   packet loss 美国
4.53.116.110    26%   packet loss 美国
173.199.5.16    15%   packet loss 美国
注:awk在处理多文件时,以谁为准,最后处理谁,即写在最后。
[[email protected] awk_file]# awk ‘NR==FNR{a[$1]=$0;next}{k=$1;$1="";print a[k]$0}‘ text1 text
PS:k=$1传递给了a[k],$1=""传递给了$0。

原文地址:http://blog.51cto.com/firelong/2069878

时间: 2024-11-10 10:37:07

文本三剑客之awk进阶篇的相关文章

Linux 文本三剑客之awk 木石前盟

前言 一.木石前盟 众所周知,我们大中华上下5千年历史,其中当属"四大名著"最让人津津乐道.<红楼梦>一书更为四大名著之首,被评为中国古典章回小说的巅峰之作,是中国最受重视的一部文学作品.此书由清代作家曹雪芹所作,故事主线为贾宝玉.林黛玉及薛宝钗三人的爱情与婚姻悲剧,以及贾府等四大家族的没落. 故事开头即提到木石前盟一事.说到林黛玉的前身是绛珠仙草,贾宝玉的前身是神瑛侍者.<红楼梦>第一回"甄士隐梦幻识通灵 贾雨村风尘怀闺秀 "中有这样一段描

linux基础篇-文本三剑客之AWK

awk介绍 ? awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出 ? 有多种版本:New awk(nawk),GNU awk( gawk) ? gawk:模式扫描和处理语言? 基本用法:awk [options] 'program' var=value file-awk [options] -f programfile var=value file-awk [options] 'BEGIN{ action;- } pattern{ action;- } E

Linux文本三剑客之awk的使用

文本处理三剑客: grep.egrep.fgrep:称为文本过滤工具 sed:称为流编辑器,行编辑器 awk:称为报告生成器,主要用于格式化文本输出 awk:Aho,Weinberher,Kernighan 由这个三个作者创建而成,最初是用在UXIN系统上面,后来被GNU组织不断对其进行更新,就形成了gawk,现在linux上用的都是gawk. [[email protected] tmp]# which awk /bin/awk [[email protected] tmp]# ll -d /

linux 文本三剑客之awk

awk简介 awk同sed.grep被称为linux文本处理三剑客,都起源于行编辑器ed.awk继承了行编辑器的特点,循环的读取文本的每一行(或者是分隔符分割的每一段文本)直至文本结束,但是awk加入了段分割符的概念.将每次读入的行进行再次分割.awk每次读取的行都只是未经过awk语句处理的对象.或读取行后会根据段分割符在将行分成多个对象.结构近似数组,然后进行指定语句的操作.作为一款报表生成器,作用是对对文本内容进行各种排版,进而格式化显示. awk有自己的语法,可以说是一款独立的编程语言.

Linux上文本三剑客之awk详解

AWK介绍 Linux 文本处理工具三剑客:grep.sed.awk.其中grep是一种文本过滤工具:sed是文本行编辑器,而awk是一种报表生成器,就是对文件进行格式化处理的,但这里的格式化不是文件系统的格式化,而是对文件内容进行各种"排版",进而格式化显示:在Linux之上我们使用的是GNU awk 简称gawk,并且gawk就是awk的链接文件,因此系统上使用的awk和gawk是一样的.gawk是一种过程式编程语言.gawk还支持条件判断.数组.循环等编程语言中所有可以使用的功能

Linux文本三剑客之awk

awk:报告生成器,格式化文本输出 AWK: Aho, Weinberger, Kernighan --> New AWK, NAWK GNU awk, gawk gawk - pattern scanning and processing language 基本用法:gawk [options] 'program' FILE ... program: PATTERN{ACTION STATEMENTS} 语句之间用分号分隔 print, printf 选项: -F:指明输入时用到的字段分隔符

文本三剑客之awk

awk awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出 awk命令形式: awk [-F|-f|-v] 'BEGIN{} //{command1; command2} END{}' file [-F|-f|-v]   大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value '  '          引用代码块 BEGIN   初始化代码块,在对每一行进行处理之

文本三剑客之awk基础操作

1. awk基本介绍 功能说明:gawk - pattern scanning and processing languageawk是GNU项目,所以其实际的命令为gawk,因awk命令的二进制文件链接到gawk,所以awk命令亦是gawk命令. 1.1 描述 Gawk is the GNU Project's implementation of the AWK programming language. It conforms to the definition of the language

linux文本三剑客匹配网卡IP地址大PK(CentOS 7系统)

    运维工程师在做配置的过程中很多时候都需要去获取目标服务器网卡上的IP地址,那究竟用什么方式获取更便捷了,博主今天就带大家使用linux文本三剑客分别获取一下网卡的IP地址,最后我们再来对比一下. 实验环境: 系统:CentOS 7.2 网卡张数:双网卡 linux文本三剑客之grep 获取ifconfig输出中的IP地址 ifconfig | egrep -o "\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-1][0-9]|22[0-3])\>.(\