一、AWK概念
awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输(stdin)、一个或多个文件,或其它命令的输出。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
二、AWK用法
1、语法格式
awk [options] 'scripts' var=value file(s)
awk [options] -f scriptfile var=value file(s)
2、常用参数
-F 指定分隔符(可以是字符串或正则表达式;如-F:)
-f 从脚本文件中读取awk命令
-v var=value 赋值变量,将外部变量传递给awk
3、内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数,执行过程中对应于当前的字段数
NR 已读的记录数,相当于行号
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。
$NF是number finally,表示最后一列的信息,跟变量NF是有区别的,变量NF统计的是每行列的总数
4、常用参数
-F 指定分隔符(可以是字符串或正则表达式)
-f 从脚本文件中读取awk命令
-v var=value 赋值变量,将外部变量传递给awk
5、AWK模式和操作
模式
/正则表达式/:使用通配符的扩展集
关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试
模式匹配表达式:用运算符~(匹配)和!~(不匹配)
BEGIN语句块、pattern语句块、END语句块
操作
操作是由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,主要部分是:变量或数组赋值、输出命令、内置函数、控制流语句
6、AWK脚本基本结构
awk 'BEGIN{ print "start" } pattern{ commads } END{ print "end" }' file
三、awk工作原理
awk 'BEGIN{ commads } pattern{ commads } END{ commads }'
第一步:执行BEGIN{ commads }语句块的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commads }语句块,它逐步扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕
第三步:当读至输入流末尾时,执行END{ commads }语句块
BEGIN{ commads }语句块 在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块
END{ commads }语句块 在awk从输入流中读取完所有的行之后即被执行,它也是一个可选语句块
pattern{ commads }语句块 中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印读取到的每一行,awk读取的每一行都会执行该语句块
示例
[root@os test]# awk '/root/' /etc/passwd #默认是打印读取到的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@os test]# awk -F: '/root/ { print $1,$NF }' /etc/passwd #以:分隔,打印第一和最后一列
root /bin/bash
operator /sbin/nologin
[root@os test]# echo -e "a line \nb line" | awk 'BEGIN{ print "start" } { print } END{ print "end" }'
start
a line
b line
end
#统计/etc/passwd文件中每行的字符数
[root@os test]# awk -F "" '{for(i=1;i<=NF;i++) if($i!="\n") ++sum;print sum;a=a+sum;sum=0}END{print "sum:"a}' /etc/passwd
四、外部变量、运算、判断
1、外部变量,借助 -v选项,可以将外部值传递给awk
[root@os test]# var=10010
[root@os test]# echo | awk -v VARIABLE=$var '{ print VARIABLE }'
10010
[root@os test]# unset var #撤消变量
2、运算
类型 | 运算符 | 描述 |
---|---|---|
算术运算符 | + - | 加,减 |
* / & | 乘,除,求余 | |
+ - ! | 一元加,减和逻辑非 | |
^*** | 求幂 | |
++ -- | 增加或减少,作为前缀或后缀 | |
赋值运算符 | =、+=、-=、/=、%=、^=、**= | 例:a+=5,等价于a=a+5,其它类同 |
逻辑运算符 | ||、&& | 逻辑或和逻辑与 |
关系运算符 | <、<=、>、>=、!=、== | |
正则运算符 | ~、!~ | 匹配正则和不匹配正则 |
其它运算符 | ? | 条件表达式 |
$ | 字段引用 | |
in | 数组中是否存在某键值 |
算术运算示例
[root@os test]# awk 'BEGIN{ a="b";print a++,++a}'
0 2
#注意:所有用作算术运算符进行操作,操作数自动转为数值,所有非操作数值变为0
赋值运算示例
[root@os test]# awk 'BEGIN{ a=4;print a+=5}'
9
[root@os test]# awk 'BEGIN{ a=4;print a*=5}'
20
逻辑运算示例
[root@os test]# awk 'BEGIN{ a=4;b=3;print (a>5 && b<4),(a>5 || b<4)}'
0 1
关系运算示例
[root@os test]# awk 'BEGIN{ a=4;if(a<5){print "ok"}}'
ok
正则运算示例
[root@os test]# awk 'BEGIN{ a="100absfc";if(a ~ /^100/){print "ok"}}'
其它运算示例
[root@os test]# awk 'BEGIN{ a="b";arr[0]="b";arr[1]="c";print (a in arr)}'
0
[root@os test]# awk 'BEGIN{ a="b";arr[0]="b";arr["b"]="c";print (a in arr)}'
1
[root@os test]# awk 'BEGIN{ a=10;print a<9?"ok":"err"}'
err
五、AWK高级输入输出
1、读取下一条记录
awk中next语句使用:在循环逐行匹配,如果遇到next,就会跳过当前行,直接忽略下面语句而进行下一行匹配。多用于多行合并
[root@os awktest]# vi test.txt
a
b
c
d
e
[root@os awktest]# awk 'NR%2==1{next}{print NR,$0}' test.txt
2 b
4 d
[root@os awktest]# vi next.txt
httpd ok
web01[192.168.1.101]
httpd ok
tomcat ok
sendmail ok
web02[192.168.1.102]
httpd ok
postfix ok
web03[192.168.1.103]
httpd ok
mysqld ok
[root@os awktest]# awk '/^web/{T=$0;next}{print T":\t"$0;}' next.txt
web01[192.168.1.101]: httpd ok
web01[192.168.1.101]: tomcat ok
web01[192.168.1.101]: sendmail ok
web02[192.168.1.102]: httpd ok
web02[192.168.1.102]: postfix ok
web03[192.168.1.103]: httpd ok
web03[192.168.1.103]: mysqld ok
2、读取一条记录
awk getline:输出重定向需要使用getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其它输入文件获得输入。它负责从输入获得下一行内容,并给NF,NR,FNR等内置变量赋值。
用法说明:
当其左在右无重写向符|或<时,getline作用于当前文件,读入当前文件的第一行给其后缀的变量var或$0,应该注意到,由于awk在处理getline之前已经读入一行,所以getline得到的返回结果是隔行的
当其左在右有重写向符|或<时,geline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行
[root@os awktest]# awk 'BEGIN{ "date" | getline out; print out }' test
Sat Mar 14 12:06:53 EDT 2020
[root@os awktest]# awk '{ getline } /root/ ' /etc/passwd
operator:x:11:0:operator:/root:/sbin/nologin #注意,这里是隔行的,所以只匹配到一个
六、流程控制语句
在linux awk的while、do-while和for语句中允许使用break,continue语句来控制流程走向,也允许exit语句退出。awk中,流程控制语句,语法结构,与C语言类似。有了这些,很多shell程序都可以交给awk,而且性能非常快
#if语句
[root@os awktest]# awk ' BEGIN{test=100;if(test>90){print "very good"}else if(test>60){print "good"}else{prit "no pass"}}'
very good
#while语句
[root@os awktest]# awk 'BEGIN{test=13;total=0;while(i<=test){total+=i;i++}print total}'
91
#for语句(2种格式)
[root@os awktest]# awk 'BEGIN{for(k in ENVIRON){print k"="ENVIRON[k];}}'
AWKPATH=.:/usr/share/awk
OLDPWD=/root
SELINUX_LEVEL_REQUESTED=
SELINUX_ROLE_REQUESTED=
......
36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
[root@os awktest]# awk 'BEGIN{for(i=0;i<=13;i++){total+=i}print total;}'
91
七、数组应用
1、数组的定义
数字帮数组索引(下标):
array[1]="sun"
array[2]="shitou"
字符串做数组索引(下标):
array["first"]="www"
array["last"]="name"
array["birth"]="1990"
[root@os awktest]# awk 'BEGIN{array[1]="sun";array[2]="shitou";array["first"]="www";array["last"]="name";array["birth"]="1990"; { print array[1] "\n" array["first"]}}'
sun
www
[root@os awktest]# awk 'BEGIN{array[1]="sun";array[2]="shitou";array["first"]="www";array["last"]="name";array["birth"]="1990"; { for(item in array){print array[item]}}}'
1990
www
name
sun
shitou
[root@os awktest]# awk 'BEGIN{array[1]="sun";array[2]="shitou";array["first"]="www";array["last"]="name";array["birth"]="1990"; { for(i=1;i<=2;i++){print array[i]};} }'
sun
shitou
2、数组相关函数
#输出数组长度
[root@os awktest]# awk 'BEGIN{info="it is a test";lens=split(info,tA," ");print length(tA), lens;}'
4 4
#length返回字符串以及数组长度,split进行分割字符串为数组,也会返回分割得到的数组长度