【文本三剑客之一awk】

一.awk是一门解释型的编程语言,适合于文本处理(行和列)和报表生成,它提供了正则表达式的匹配,流程控制,运算符,表达式,变量以及函数等一系列的程序设计语言所具备的特性。

简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。三个版本:awk,nawk,gawk,一般未做说明是指gwak,gwak是awk的GNU版本。

[root@node1 ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 215 20:38 /usr/bin/awk -> gawk

1.grep、sed、awk区别:

在这里插入图片描述

2.awk工作过程:

在这里插入图片描述
第一步:执行BEGIN{ation;…}语句块,与文件无关。
第二步:从文件或STDIN中读取一行,然后执行pattern{ation;…}语句块,它逐行扫描文本内容,从第一行和最后一行重负这个过程,直到文本内容全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块

BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选语句块,通常变量初始化、打印输出表格的表头等语句写在BEGIN语句块中。
pattern语句块中的命令式最重要的部分,也是可选的,满足pattern模式条件时,才会执行action动作,如果没有提供pattern语句块,则默认执行{print},即打印每一个读取的行,awk读取的每一行都会执行该语句块。

[root@node1 day4]# awk '{print}' 1.txt
asss

END语句块在awk偶从输入流读取完所有航之后就被执行,,也是可选的通常打印所有航的分析结果这类信息汇总在end语句块执行。
如果没有begin和end,但一定要有pattern{action,...}部分,或只有pattern{action,...}和end两部分

[root@node1 day4]# awk 'BEGIN {print "hello world!"}' 
hello world!

3.awk中的行和列

在这里插入图片描述
每个字段都有对应的变量来表示:

变量含义
$0读入的整行
$1第一个字段
$n第n个字段

注:awk列标识是从$1开始的,且$0表示行,与shell脚本中的$0表示脚本名不同。

4.awk的基本语法

语法:awk [options] 'BEGIN {action;...} pattern {action;... } END{action;...}' file1 file2, ...
1.省略pattern:默认匹配所有行,执行action语句
读取/etc/fstab文本的所有航,并在每一行的位置打印hello

[root@node1 ~]# awk '{print "hello"}' /etc/fstab
hello
hello
hello
hello

2.BEGIN语句:不处理文件,直接执行action语句

[root@node1 ~]# awk 'BEGIN {print "begin..."}'
begin...

3.默认的字段分隔符:默认的输入字段分隔符空格,默认的输出字段分隔符也是空格

[root@node1 ~]# df | awk '{print $1,$5}'
文件系统 已用%
devtmpfs 0%
tmpfs 0%
tmpfs 2%
tmpfs 0%
/dev/mapper/centos-root 15%
/dev/sr0 100%
/dev/sda1 20%
tmpfs 0%

4.-F:指定输入字段分隔符

[root@node1 ~]# awk -F : '{print $1":"$3}' /etc/passwd
root:0
bin:1

5.awk 输出:print、printf、输出重定向

1)print的使用格式:

{print item1, item2, ...}
要点:
1. 各项目之间使用逗号隔开,而输出时则以空白字符分隔;
2. 输出的item可以为"字符串"、数值、当前记录的字段(如$1)、变量或awk的表达式;数值会先转换为字符串,而后再输出;
3. print命令后面的item可以省略,此时其功能相当于print $0,这样就输入文件的全部内容, 因此,如果想输出空白行,则需要使用print “”;

[root@node1 ~]# awk 'BEGIN {print " "}' 
 
[root@node1 ~]# awk -F : '{print "user:",$1,$2}' passwd
user: root x
user: bin x
[root@node1 ~]# awk -F : '{print "user:",$1,$2,2+3}' passwd
user: root x 5
user: bin x 5
#之后,会被替换成输出分隔符空格
[root@node1 ~]# awk 'BEGIN {print "one\n","two"}'
one
 two
[root@node1 ~]# awk 'BEGIN {print "one\n""two"}'
one
two

2)printf命令的使用格式:

{printf "item1指定格式 item2指定格式 ....\n",item1, item2, ...}
要点:
1.其与print命令的最大不同是,printf需要指定format格式;
2.format格式用于指定后面的每个item的输出格式;
3.printf语句不会自动打印换行符,所有后面要加\n

格式符以%开头,后跟一个字符
%c显示字符的ASCII码
%d, %i十进制整数;
%e, %E科学计数法显示数值;
%f显示浮点数;
%g, %G以科学计数法的格式或浮点数的格式显示数值;
%s显示字符串;
%u无符号整数;
%%显示%自身;
修饰符:
N数字显示宽度; eg:%-20s
-左对齐; eg:%-20s
+显示数值符号
[root@node1 ~]# awk -F: '{printf "%s %d\n",$1,$3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
root 0
bin 1
daemon 2
adm 3

3)输出重定向的使用格式

{print items > output-file}
{print items >> output-file}
{print items | command}

[root@node1 ~]# awk -F: '{printf "%-10s %d\n",$1,$3 > "test1"}' /etc/passwd

6.awk 变量

1)awk内置变量之记录变量

1.FS输入字段分隔符:读取文件本时,所使用字段分隔符;等价于 -F"字段分隔符"

[root@node1 ~]# awk 'BEGIN {FS=":"}{print $1,$3}' passwd
root 0
bin 1

2.OFS输出字段分隔符

[root@node1 ~]# awk -F: 'BEGIN {OFS="#"}{print $1,$3}' passwd
root#0
bin#1

2)awk内置变量之数据变量

1NR: 记录行编号;如果有多个文件,这个数目会把处理的多个文件中行统一计数;

[root@node1 ~]# awk '{print NR}' yes.txt
1
2
3
4

若要输出第几行,就可以使用NR内置变量:

[root@node1 ~]# awk 'NR==1' yes.txt
anaconda-ks.cfg s qc

FNR: awk可能处理多个文件,各自文件计数
#记录多个文件的行号:FNR

[root@node1 ~]# awk '{print FNR}' yes.txt total.txt
1
2
3
4
1
2
3
4
5
6

2.NF:当前记录的字段个数
#统计每一行字段的个数

[root@node1 ~]# awk '{print NF}' yes.txt
3
2
2
2

#打印每一行的最后一个

[root@node1 ~]# awk '{print $NF}' yes.txt
qc
ds
c
.txt

3.ENVIRON:当前shell环境变量及其值的关联数组;
#打印当前shell环境变量

root@node1 ~]# awk 'BEGIN{print ENVIRON["PATH"]}'
/usr/java/jdk1.8.0_60/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

3)用户自定义变量

变量名命名规则与大多数编程语言相同,只能使用字母、数字和下划线,且不能以数字开头。gawk变量名称区分字符大小写。
方法1:使用-v选项:awk -v 变量名="变量值" '语句块'

[root@node1 ~]# awk -v msg="hello world" 'BEGIN{print msg}'
hello world

方法2:在action语句块中进行定义:{变量名="变量值";...}

[root@node1 ~]# awk 'BEGIN{test="hello";print test}'
hello

7.awk操作符

1) 算术操作符

-x负值
+x转换为数值
x^y次方
x**y次方
x*y
x/y
x+y
x-y
x%y求模
[root@node1 ~]# awk 'BEGIN{x=2;y=3;print x**y,x^y,x*y,x/y,x+y,x-y,x%y}'
8 8 6 0.666667 5 -1 2

2)字符串操作符:只有一个,而且不用写出来,用于实现字符串拼接,那就是冒号""

[root@node1 ~]# awk 'BEGIN {print "this","is","test"}'
this is test

3) 赋值操作符

=赋值
+=加赋值
-=减赋值
*=乘赋值
/=除赋值
%=求模赋值
^=次方赋值
**=次方赋值
++自增
自减

需要注意的是,如果某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替代

[root@node1 ~]# awk 'BEGIN {x=2;y=x;print x++,y--,++x,--y}'
2 2 4 0

4) 布尔值:任何非0值或非空字符串都为真,反之就为假;
5) 比较操作符

x<y小于
x<=y小于等于
x > y大于
x >= y大于等于
x == y等于
x != y不等于
x ~ y匹配
x !~ y不匹配
[root@node1 ~]# awk -F : '$3==0 {print $1}' /etc/passwd
root
[root@node1 ~]# awk -F : '$3>1000 {print $1,$3}' /etc/passwd
jack 1001
student 2000

#~表示匹配

[root@node1 ~]# awk -F : '$0~"root" {print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@node1 ~]# awk -F : '$0~"^root" {print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

6) 逻辑关系符:&& ||

[root@node1 ~]# awk -F : '$3>1000&&$4>1000 {print $1,$3,$4}' /etc/passwd
jack 1001 1001
[root@node1 ~]# awk -F : '$3>1000||$4>1000 {print $1,$3,$4}' /etc/passwd
jack 1001 1001
student 2000 0

7) 条件表达式:三目运算符selector?if-true-exp:if-false-exp
#使用条件测试表达式打印出每行的最大值:
awk ‘{max=$1>$2?$1:$2;print NR,“max =”,max}’ num

8.awk 模式:pattern { action }

常见的模式类型:
1.正则表达式,格式为/regular expression/

[root@node1 ~]# awk '/^root/' passwd
root:x:0:0:root:/root:/bin/bash
[root@node1 ~]# sed -n '/^root/ p' passwd
root:x:0:0:root:/root:/bin/bash
[root@node1 ~]# grep '^root' passwd
root:x:0:0:root:/root:/bin/bash

2.表达式,其值非0或为非空字符时满足条件,如:$1 ~ /foo/ 或 $1 =="uplook",用运算符~(匹配)和!~(不匹配)。

[root@node1 ~]# awk -F: '$0~/root/' passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@node1 ~]# awk -F: '/^root/,/^bin/' passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

3.指定的匹配范围,格式为pat1,pat2
4.BEGIN/END:特殊模式,仅在awk命令执行前运行一次或结束前运行一次

[root@node1 ~]# awk -F: 'BEGIN {print "开始处理"} /^root/,/^bin/' passwd
开始处理
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@node1 ~]# awk -F: 'BEGIN {print "开始处理"};/^root/,/^bin/;END{print "处理结束"}' passwd
开始处理
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
处理结束
[root@node1 ~]# awk -F: 'BEGIN {printf "%-20s %s\n","USER","UID"} {printf "%-20s %s\n",$1,$3}' passwd
USER                 UID
root                 0
bin                  1
daemon               2
adm                  3
lp                   4
[root@node1 ~]# awk -F: 'BEGIN {printf "%-15s %-3s %-15s\n","user","uid","shell"} $3==0,$7~"nologin" {printf "%-15s %-3s %-15s\n",$1,$3,$7} END {print "-----End file-----"}' /etc/passwd
user            uid shell          
root            0   /bin/bash      
bin             1   /sbin/nologin  
-----End file-----

5.Empty(空模式):匹配任意输入行

9.awk 控制语句

1)if-else
语法:if(表达式) {语句1} else if(表达式) {语句2} else {语句3}

[root@node1 ~]# awk 'BEGIN {x=2;y=3; if(x>y) {print "x>y"} else if (x<y) {print "x<y"} else {print "x=y"}}'
x<y
[root@node1 ~]# awk -F: '{if ($3==0) {print $1,"管理员"} else {print $1,"普通用户"}}' /etc/passwd
root 管理员
bin 普通用户

2)while循环
语法: while(表达式) {语句}

[root@node1 ~]# awk 'BEGIN {i=1;while(i<=10) {sum+=i;i++};{print sum}}'
55

3)do-while
语法: do{语句}while(条件)

[root@node1 ~]# awk 'BEGIN {i=1;do{sum+=i;i++} while(i<=10);{print "1+2+...5=",sum}}'
1+2+...5= 55

4)for循环
格式1:for(变量;条件;表达式){语句}

[root@node1 ~]# awk 'BEGIN{for (i=1;i<=5;i++){sum+=i} print sum}'
15

格式2遍历数组: for(变量 in 数组){语句}
主要用于统计文件重复行中的某些列出现的次数

[root@node1 ~]# awk -F : '{shell[$NF]++} END {for (k in shell) {print k,shell[k]}}' /etc/passwd
/bin/sync 1
/bin/bash 7
/sbin/nologin 17
/sbin/halt 1
/sbin/shutdown 1

5)case多分支
语法:switch (expression) { case VALUE or /REGEXP/: statement1, statement2,... default: statement1, ...}
6)break 和 continue:常用于循环或case语句中
7)next提前结束对本行文本的处理,并接着处理下一行;

[root@node1 ~]# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
bin 1
adm 3

10.awk使用数组

1)数组
array[index-expression]
for (var in array) { statement1, … }
其中,var用于引用数组下标,而不是元素值;

[root@node1 ~]# netstat -ant | awk '{con[$NF]++} END{for (v in con) {print con[v],v}}' | sort -nr
5 LISTEN
1 State
1 ESTABLISHED
1 established)
[root@node1 ~]# netstat -nalp | awk '/^tcp/ {print $5}' | awk -F: '{IP[$1]++} END{for (v in IP) {print IP[v],v}}' | sort -nr
3 
2 0.0.0.0
1 192.168.131.201

2)删除数组变量:delete array[index]

11.awk内置函数

1.split(string, array [, fieldsep [, seps ] ])
功能:将string表示的字符串以fieldsep为分隔符进行分隔,并将分隔后的结果保存至array为名的 数组中;数组下标为从0开始的序列;

# date +%T | awk '{split($0,a,":");print a[1],a[2],a[3]}'

2.length([string])
功能:返回string字符串中字符的个数;

# awk 'BEGIN{print length("uplooking")}'
[root@node1 ~]# awk -F: 'length($1)>3' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin

3.substr(string, start [, length])
功能:取string字符串中的子串,从start开始,取length个;start从1开始计数;

[root@node1 ~]# awk 'BEGIN{print substr("hello",2,2)}'
el
[root@node1 ~]# awk 'BEGIN{print substr("hello",2)}'
ello

4.system(command)
功能:执行系统command并将结果返回至awk命令

[root@node1 ~]# awk 'BEGIN{print system("whoami")}'
root
0
[root@node1 ~]# awk 'BEGIN{print system("date")}'
20200705日 星期日 14:52:56 CST

5.systime()功能:取系统当前时间

# awk 'BEGIN{print systime()}'

6.tolower(s)功能:将s中的所有字母转为小写

# awk 'BEGIN{print tolower("WWW.baidu.COM")}'

7.toupper(s)功能:将s中的所有字母转为大写

# awk 'BEGIN{print toupper("WWW.baidu.COM")}'

12练习:

#获取网卡接口名

[root@node1 ~]# ifconfig | awk -F: '/flags/ {print $1}'
ens33
lo
[root@node1 ~]# ip a | awk -F"[ :]" '/^[0-9]/ {print $3}'
lo
ens33

练习:
编写文件file的内容如下:
Mike Harrington:[510] 548-1278:250💯175
Christian Dobbins:[408] 538-2358:155:90:201
Susan Dalsass:[206] 654-6279:250:60:50
Archie McNichol:[206] 548-1348:250💯175
Jody Savage:[206] 548-1278:15:188:150
Guy Quigley:[916] 343-6410:250💯175
Dan Savage:[406] 298-7744:450:300:275
Nancy McNeil:[206] 548-1278:250:80:75
John Goldenrod:[916] 348-4278:250💯175
Chet Main:[510] 548-5258:50:95:135
Tom Savage:[408] 926-3456:250:168:200
Elizabeth Stachelin:[916] 440-1763:175:75:300
其中:
Mike Harrington 名字
[510] 548-1278 电话
250💯175 过去三个月里的捐款

(1)显示所有电话号码

[root@node1 ~]# awk -F: '{print $2}' file
[510] 548-1278
[408] 538-2358
[206] 654-6279
[206] 548-1348
[206] 548-1278
[916] 343-6410
[406] 298-7744
[206] 548-1278
[916] 348-4278
[510] 548-5258
[408] 926-3456
[916] 440-1763

(2)显示Dan的电话号码

[root@node1 ~]# awk -F: '/Dan/ {print $2}' file
[406] 298-7744

(3)显示Susan的名字和电话号码

[root@node1 ~]# awk -F: '/Susan/ {print $1,$2}' file
Susan Dalsass [206] 654-6279

(4)显示所有以D开头的姓

[root@node1 ~]# awk -F"[ :]" '{print $2}' file| awk '/^D/'
Dobbins
Dalsass
[root@node1 ~]# awk -F: '{print $1}' file |awk '{print $2}' |awk '/^D/'
Dobbins
Dalsass

(5)显示所有以一个C或E开头的名

[root@node1 ~]# awk -F"[ :]" '/^[CE]/ {print $1}' file
Christian
Chet
Elizabeth
[root@node1 ~]# awk '/^[CE]/' file | awk '{print $1}'
Christian
Chet
Elizabeth
[root@node1 ~]# awk -F"[ :]" '$1~/^[CE]/ {print $1,$2}' file
Christian Dobbins
Chet Main
Elizabeth Stachelin

(6)显示所有只有四个字符的名,这里可以使用length函数

[root@node1 ~]# awk  'length($1)==4 {print $1}' file
Mike
Jody
John
Chet

(7)显示所有区号为916的人名

[root@node1 ~]# awk -F: '/916/ {print $1}' file
Guy Quigley
John Goldenrod
Elizabeth Stachelin

(8)显示Mike的捐款.显示每个值时都有以$开头.如$250$100$175

[root@node1 ~]# awk -F: '/Mike/ {print "$"$3"$"$4"$"$5}' file
$250$100$175

(9)显示姓,其后跟一个逗号和名

[root@node1 ~]# awk -F: '{print $1}' file | awk '{print $2","$1}'
Harrington,Mike
Dobbins,Christian
Dalsass,Susan
McNichol,Archie
Savage,Jody
Quigley,Guy
Savage,Dan
McNeil,Nancy
Goldenrod,John
Main,Chet
Savage,Tom
Stachelin,Elizabeth

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑着蜗牛追汤圆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值