文章目录
- 一.awk是一门解释型的编程语言,适合于文本处理(行和列)和报表生成,它提供了正则表达式的匹配,流程控制,运算符,表达式,变量以及函数等一系列的程序设计语言所具备的特性。
- 1.grep、sed、awk区别:
- 2.awk工作过程:
- 3.awk中的行和列
- 4.awk的基本语法
- 5.awk 输出:print、printf、输出重定向
- 1)print的使用格式:
- 2)printf命令的使用格式:
- 3)输出重定向的使用格式
- 6.awk 变量
- 1)awk内置变量之记录变量
- 2)awk内置变量之数据变量
- 3)用户自定义变量
- 7.awk操作符
- 8.awk 模式:pattern { action }
- 9.awk 控制语句
- 10.awk使用数组
- 11.awk内置函数
- 12练习:
一.awk是一门解释型的编程语言,适合于文本处理(行和列)和报表生成,它提供了正则表达式的匹配,流程控制,运算符,表达式,变量以及函数等一系列的程序设计语言所具备的特性。
简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。三个版本:awk,nawk,gawk,一般未做说明是指gwak,gwak是awk的GNU版本。
[root@node1 ~]# ll /usr/bin/awk
lrwxrwxrwx. 1 root root 4 2月 15 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")}'
2020年 07月 05日 星期日 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