shell编程--三剑客之awk

一、awk基础语法(常用,其他不常用)

语法:

awk  [选项]  ‘条件{动作}  条件{动作}’  文件名 ...

1、内置变量

变量名 描述
FILENAME 当前输入文件的名称
FNR 当前输入文档的当前行号,尤其当有多个输入文档时有用
NR 输入数据流的当前行号
$0 当前行的全部内容
$n 当前行的第n个字段内容(n>1)
NF 当前记录(行)的字段(列)个数
FS 字段分隔符,默认为空格或Tab制表符
OFS 输出字段分隔符,默认为空格
ORS 输出行分隔符,默认换行符为\n
RS 输入行分隔符,默认换行符为\n
[root@www jiaofan]# free | awk '{print $2}'    #<==打印第二列
used
995672
2097148
[root@www jiaofan]# free | awk '{print NR}'    #<==输出行号
1
2
3
[root@www jiaofan]# free | awk '{print NF}'    #<==输出每行的列数
6
7
4
[root@www jiaofan]# free | awk '{print $NF}'    #<==打印最后一列
available
287716
2097148
[root@www jiaofan]# free | awk '{print $(NF-1)}'    #<==打印倒数第二列
buff/cache
288292
0
[root@www jiaofan]# cat test1.txt               #<==文件1
hello world!
other men live to eat,while I eat to live.
It is never too late to mend.
[root@www jiaofan]# cat test2.txt               #<==文件2
biscuit:crisp:chichen
salt-jam:oil,suger
banana:lemon,pear--apple:grape
[root@www jiaofan]# awk '{print $2}' test1.txt    #<==输出第一列
world!
men
is
[root@www jiaofan]# awk '{print $0}' test1.txt    #<==输出每行的全部内容
hello world!
other men live to eat,while I eat to live.
It is never too late to mend.
[root@www jiaofan]# awk '{print}' test1.txt       #<==输出每行的全部内容
hello world!
other men live to eat,while I eat to live.
It is never too late to mend.
[root@www jiaofan]# awk '{print NR}' test1.txt test2.txt   #<==打印当前行号
1
2
3
4
5
6
[root@www jiaofan]# awk '{print FNR}' test1.txt test2.txt   #<==打印当前文件行号
1
2
3
1
2
3
[root@www jiaofan]# awk  '{print FILENAME}'  test1.txt test2.txt 
test1.txt
test1.txt
test1.txt
test2.txt
test2.txt
test2.txt
[root@www jiaofan]# 

2、自定义变量(-v)

[root@www jiaofan]# awk -v x="jiaofan"  -v y=11  '{print x,y}' test1.txt
jiaofan 11
jiaofan 11
jiaofan 11
[root@www jiaofan]# x="hello"
[root@www jiaofan]# awk -v i=$x '{print i}' test1.txt   #<==输出变量
hello
hello
hello
[root@www jiaofan]# awk '{print "'$x'"}' test1.txt      #<==输出变量
hello
hello
hello

定义分隔符:FS 或 F

[root@www jiaofan]# cat test2.txt
biscuit:crisp:chichen
salt-jam:oil,suger
banana:lemon,pear--apple:grape
[root@www jiaofan]# awk -v FS=":" '{print $1}' test2.txt         #<==以:为分隔符
biscuit
salt-jam
banana
[root@www jiaofan]# awk -v FS="[:,-]"  '{print $1}' test2.txt    #<==以:和-为分隔符
biscuit
salt
banana
[root@www jiaofan]# awk -F":" '{print $1}' test2.txt             #<==以:为分隔符
biscuit
salt-jam
banana
[root@www jiaofan]# awk -F"[:,-]"  '{print $1}' test2.txt        #<==以:和-为分隔符
biscuit
salt
banana
[root@www jiaofan]# 

输入行分隔符,默认是\n,可以修改RS自定义分隔符

[root@www jiaofan]# cat test1.txt
hello world!
other men live to eat,while I eat to live.
It is never too late to mend.
[root@www jiaofan]# awk -v RS="," '{print $1}' test1.txt
hello
while

上面以逗号问行分隔符,所以输入内容为两行分别是
hello world!\nother men live to eat
while I eat to live.\nIt is never too late to mend.

输出字段分隔符OFS

[root@www jiaofan]# awk '{print $3,$1,$3}' test1.txt          #<==默认是空格为分隔符
 hello 
live other live
never It never
[root@www jiaofan]# awk -v OFS=":" '{print $3,$1,$3}' test1.txt    #<==设置冒号为分隔符
:hello:
live:other:live
never:It:never
[root@www jiaofan]# awk -v OFS="-" '{print $3,$1,$3}' test1.txt
-hello-
live-other-live
never-It-never
[root@www jiaofan]# awk -v OFS="\t" '{print $3,$1,$3}' test1.txt   #<==设置制表符为分隔符
	hello	
live	other	live
never	It	never
[root@www jiaofan]# awk -v OFS="." '{print NR,$0}' test1.txt
1.hello world!
2.other men live to eat,while I eat to live.
3.It is never too late to mend.

输出行分隔符ORS

[root@www jiaofan]# cat test1.txt
hello world!
other men live to eat,while I eat to live.
It is never too late to mend.
[root@www jiaofan]# awk -v ORS=":" '{print}'  test1.txt
hello world!:other men live to eat,while I eat to live.:It is never too late to mend.:

3、print 指令

[root@www jiaofan]# awk '{print "data:",$1}' test1.txt
data: hello
data: other
data: It
[root@www jiaofan]# awk '{print 12345}' test1.txt
12345
12345
12345
[root@www jiaofan]# awk '{print $1,12345,$3}' test1.txt
hello 12345 
other 12345 live
It 12345 never
[root@www jiaofan]# awk '{print "第一列",$1,"\t第二列:",$2}' test1.txt
第一列 hello 	第二列: world!
第一列 other 	第二列: men
第一列 It 	第二列: is

4、条件匹配

比较符号 描述
// 全行数据正则匹配
!// 对全行数据正则匹配后取反
~// 对特定数据正则匹配
!~// 对特定数据正则匹配后取反
== 等于
!= 不等于
> 大于
>= 大于等于
< 小于
<= 小于等于
&& 逻辑与,如A&&B,要求满足A并且满足B
|| 逻辑或,如A||B,要求满足A或者满足B
[root@www jiaofan]# cat test1.txt                  #<==准备素材
hello the world!
other men live to eat,while I eat to live.
It is never too late to mend.
[root@www jiaofan]# awk '/the/'  test1.txt         #<==每行正则匹配the
hello the world!
other men live to eat,while I eat to live.
[root@www jiaofan]# awk '$2~/the/'  test1.txt      #<==每行第二列正则匹配the
hello the world!
[root@www jiaofan]# awk '$4==to'  test1.txt        #<==每行第四列精确匹配the
hello the world!
[root@www jiaofan]# awk -F: '$3>=100' /etc/passwd
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
nisuser1:x:1001:1001::/home/nisuser1:/bin/bash
nisuser2:x:1002:1002::/home/nisuser2:/bin/bash
nisuser3:x:1003:1003::/home/nisuser3:/bin/bash
[root@www jiaofan]# awk 'NR==4' /etc/passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
[root@www jiaofan]# awk -F: '$3>1 && $3<5' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@www jiaofan]# awk -F: '$3==1 || $3==5' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
[root@www jiaofan]# 

awk 的匹配条件可以使BEGIN 或 END(大写字母),BEGIN 会导致动作指令仅在读取任何数据记录之前执行一次,END 会导致动作指令仅在读取完所有数据记录后执行一次。利用 BEGIN 我们可以进行数据的初始化操作,而 END 则可以帮助我们进行数据的汇总操作。

[root@www jiaofan]# awk -F:  'BEGIN{print "用户名 UID 解释器"}  {print $1,$3,$7}  END{print "总计有"NR"个账户。"}'  /etc/passwd | column -t
用户名            UID    解释器
root              0      /bin/bash
bin               1      /sbin/nologin
daemon            2      /sbin/nologin
... ...
总计有25个账户。
[root@www jiaofan]# awk 'BEGIN{print 10-4}'
6
[root@www jiaofan]# awk 'BEGIN{x=8;y=2;print x-y}'     #<==对变量进行减法
6

在awk中变量不需要定义就可以直接使用,作为字符处理时未定义的变量默认值为空,作为数字处理时未定义的变量默认值为0

[root@www jiaofan]# awk 'BEGIN{print x+8}'
8
[root@www jiaofan]# awk 'BEGIN{print "["x"]","["y"]"}'
[] []
[root@www jiaofan]# who | awk '$1=="root"{x++} END{print x}' 
2
[root@www jiaofan]# ls -l /etc/*.conf | awk '{sum+=$5} END{print sum}'
44107
[root@www jiaofan]# ls -l /etc/*.conf | awk '/^-/{sum+=$5} END{print "文件总量:"sum"."}'
文件总量:44107.
[root@www jiaofan]# 

二、条件判断

awk单支语句

if(判断条件){
动作指令序列;
}

awk双支语句

if(判断条件){
动作序列1;
}
else{
动作序列2;
}

awk多支语句

if(判断条件1){
动作序列1;
}
else if(判断条件2){
动作序列1;
}
else{
动作序列2;
}

三、awk 数组

一维数组:
数据名[索引]=值
多维数组:
数据名[索引1][索引2]=值
或者
数据名[索引1,索引2]=

for循环读取索引

for(变量 in 数据名){
动作指令序列
}

判断索引是否为数组成员

if (索引 in 数据)

四、awk 循环

for循环

for(表达式1;表达式2;表达式3){
动作指令序列
}

while 循环

while(条件判断){
动作指令序列;
}

五、awk 函数

1、内置I/O函数

函数 说明
getline getline会读取下一条数据,而不会影响后续awk指令的执行
next next不仅读取下一行数据,会导致后续的指令不再执行,而是重新读取数据后重新回到awk指令的开始位置,重新匹配,重新执行动作指令
system(“命令”) awk会启动一个新的shell进程执行命令
[root@www jiaofan]# cat test.txt 
1:hello the world.
2:go spurs air.
3:123 456 789.
4:hello the beijing.
[root@www jiaofan]# awk '/air/{getline;print "next line:",NR,$0} {print "noraml line NR="NR}' test.txt
noraml line NR=1
next line: 3 3:123 456 789.
noraml line NR=3
noraml line NR=4
[root@www jiaofan]# awk '/air/{next;print "next line:",$0} {print "noraml line NR="NR}' test.txt
noraml line NR=1
noraml line NR=3
noraml line NR=4
[root@www jiaofan]# awk 'BEGIN{system("uptime")}'
 16:44:45 up  6:56,  3 users,  load average: 0.00, 0.01, 0.05
[root@www jiaofan]# awk 'BEGIN{system("echo jiaofan")}'
jiaofan

2、内置数值函数

函数 说明
cos(expr) 函数返回expr的cosine值
sin(expr) 函数返回expr的sine值
sqrt(expr) 函数返回expr的平方
int(expr) 函数为取整函数,仅截取整数部分的数值
rand() 函数可以返回0到1之间的随机数N(0<=N<1)
srand() 函数可以使用expr定义新的随机数种子,没有expr时则使用当前系统的时间为随机数种子
[root@www jiaofan]# awk 'BEGIN{print cos(50)}'
0.964966
[root@www jiaofan]# awk 'BEGIN{print sin(50)}'
-0.262375
[root@www jiaofan]# awk 'BEGIN{print sqrt(2)}'
1.41421
[root@www jiaofan]# awk 'BEGIN{print sqrt(4)}'
2
[root@www jiaofan]# awk 'BEGIN{print int(4.6)}'    
4
[root@www jiaofan]# awk 'BEGIN{print rand()}'             
0.237788
[root@www jiaofan]# awk 'BEGIN{for(i=1;i<=5;i++)print rand()}'
0.237788
0.291066
0.845814
0.152208
0.585537
[root@www jiaofan]# awk 'BEGIN{print 100*rand()}'
23.7788
[root@www jiaofan]# awk 'BEGIN{print rand()}'              #<==没有新种子随机数固定      
0.237788
[root@www jiaofan]# awk 'BEGIN{srand();print rand()}'      #<==使用时间做随机数
0.217179
[root@www jiaofan]# awk 'BEGIN{srand(897);print rand()}'   #<==使用897做随机数 
0.504158
[root@www jiaofan]# awk 'BEGIN{srand(897);print rand()}'
0.504158

3、内置字符串函数

length([s]) 函数可以统计字符串s的长度,如果不指定字符串 s 则统计$0的长度。

[root@www jiaofan]# awk 'BEGIN{test="hello the world";print length(test)}'
15

index(字符串1,字符串2) 函数返回字符串2在字符串1中的位置坐标。

[root@www jiaofan]# awk 'BEGIN{test="hello the world";print index(test,"h")}'          #<==h在test变量的第一个位置
1
[root@www jiaofan]# awk 'BEGIN{test="hello the world";print index(test,"t")}'          #<==t在test变量的第一个位置
7

match(s,r) 函数根据正则表达式 r 返回其在字符串s中的位置坐标。

[root@www jiaofan]# awk 'BEGIN{print match("How much? 981$","[0-9]")}'   #<==数字在第11个位置出现
11
[root@www jiaofan]# awk 'BEGIN{print match("How 4much? 981$","[0-9]")}'    #<==数字在第5个位置出现
5 
[root@www jiaofan]# awk 'BEGIN{print match("How much? 981$","[a-z]")}'
2
[root@www jiaofan]# awk 'BEGIN{print match("How much? 981$","[A-Z]")}'
1

tolower(str) 函数可以将字符串转换为小写

[root@www jiaofan]# awk 'BEGIN{apple[0]="red aPPLe";print tolower(apple[0])}'
red apple

toupper(str) 函数可以将字符串转换为大写。

[root@www jiaofan]# awk 'BEGIN{apple[0]="red aPPLe";print toupper(apple[0])}'
RED APPLE

split(字符串,数组,分隔符) 函数可以将字符串按特定的分隔符切片后存储在数组中,如果没有指定分隔符,则使用FS定义的分隔符进行字符串分隔。

[root@www jiaofan]# awk 'BEGIN{split("hello the world",test);print test[1],test[2]}'
hello the

这条命令以空格或Tab键为分隔符,将hello the world 切割为独立的三个部分,分别存入 test[1]、test[2]、test[3] 数组中,最后通过 print 指令可以按照任意顺序打印显示这些数组元素的值。

[root@www jiaofan]# awk 'BEGIN{split("hello:the:world",test);print test[1] test[2]}'          #<==test[2]为空值
hello:the:world
[root@www jiaofan]# awk 'BEGIN{split("hello:the:world",test,":");print test[1] test[2]}'          #<==自定义分隔符为冒号
hellothe
[root@www jiaofan]# awk 'BEGIN{split("hello:the:world",test,":");print test[1],test[2]}'          
hello the
[root@www jiaofan]# awk 'BEGIN{split("hi8the3world4!",test,"[0-9]");print test[1],test[4]}'     #<==使用正则定义分隔符
hi !
[root@www jiaofan]# 

gsub(r,s,[,t]) 函数可以将字符串 t 中所有的正则表达式 r 匹配的字符串全部替换为 s ,如果没有指定字符串 t ,默认对$0进行替换操作。

[root@www jiaofan]# awk 'BEGIN{hi="hello world";gsub("o","O",hi);print hi}'    #<==小写o换成大写O
hellO wOrld
[root@www jiaofan]# head -1 /etc/passwd | awk '{gsub("[0-9]","**");print $0}'    #<==全部的数字替换成**
root:x:**:**:root:/root:/bin/bash

sub(r,s,[,t]) 函数与gsub类似,但仅替换第一个匹配的字符串,而不是替换全部。

[root@www jiaofan]# head -1 /etc/passwd | awk '{sub("[0-9]","**");print $0}'
root:x:**:0:root:/root:/bin/bash
[root@www jiaofan]# head -1 /etc/passwd | awk '{sub("root","**");print $0}'
**:x:0:0:root:/root:/bin/bash

substr(s,i[,n]) 函数可以对字符串s 进行截取,从第i位开始,截取n个字符串,如果n没有指定则一直截取到字符串s的末尾位置。

[root@www jiaofan]# awk 'BEGIN{hi="hello world";print substr(hi,2,3)}'    #<==从第2位开始截取3个字符
ell    
[root@www jiaofan]# awk 'BEGIN{hi="hello world";print substr(hi,2)}'   #<==从第2位开始截取到末尾
ello world

4、内置时间函数

systime() 返回当前时间距离1970-01-01 00:00:00 有多少秒。

[root@www jiaofan]# awk 'BEGIN{print systime()}'
1646017041
[root@www jiaofan]# 

你可能感兴趣的:(linux,shell,核心编程,bash,服务器,linux,运维,centos)