1、awk语法:
awk [选项] '条件1{动作1} 条件2{动作2} ……' 文件名
选项:
-F:fs fs指定输入分隔符,fs可以是字符串或正则表达式。
-v:var=value 赋值一个用户自定义变量,将外部变量传递给awk。
-f:scriptfile 从脚本文件中读取awk命令。
条件:一般使用关系表达式作为条件。
动作:格式化输出;流程控制语句。
2、awk的条件:
条件的类型 | 条 件 | 说 明 |
awk 保留字 | BEGIN | 在awk程序一开始时,尚未读取任何数据之前执行。BEGIN之后的动作只在程序开始时执行一次。 |
END | 在awk程序处理完所有数据,即将结束时执行。END后的动作只在程序结束时执行一次。 | |
关系运算符 | > | 大于 |
< | 小于 | |
>= | 大于等于 | |
<= | 小于等于 | |
== | 等于。用于判断两个值是否相等。区别于变量赋值“=”。 | |
!= | 不等于 | |
A~B | 判断字符串A中是否包含能匹配B表达式的子字符串 | |
A!~B | 判断字符串A中是否不包含能匹配B表达式的子字符串 | |
正则表达式 | // | //中可以写入字符,也支持正则表达式 |
3、BEGIN的用法:
BEGIN的执行时机是“在awk一开始,尚未读取任何数据之前执行”。一旦BEGIN后的动作执行一次,BEGIN的条件就不再成立。
[root@master ~]# awk 'BEGIN{print "Hell World!"} {print $1"\t"$2}' /etc/hosts Hell World! 127.0.0.1 localhost ::1 localhost 192.168.1.201 master
4、END的用法:
END是在awk处理完所有数据,即将结束时执行。END的动作只在程序结束时执行一次。
[root@master ~]# awk 'END{print "The End"} {print $1"\t"$2}' /etc/hosts 127.0.0.1 localhost ::1 localhost 192.168.1.201 master The End
5、使用关系运算符:
用到的示例文件内容如下。
[root@master ~]# cat students.txt ID Name MySQL Linux Nginx Average 1 Lisan 86 95 82 87.66 2 Sunsi 96 87 74 85.66 3 Wangwu 93 99 83 91.66
想知道平均成绩超过90分的学生姓名:
[root@master ~]# awk '$6>=90{print $2}' students.txt | grep -v Name Wangwu
awk命令的执行过程:
1) 如果有BEGIN条件,则先执行BEGIN定义的动作;
2) 如果没有BEGIN条件,则读入第一行,把第一行的数据依次赋予$0、$1、$2等变量。其中$0代表此行的整体数据,$1代表第一字段,$2代表第二字段;
3) 依据条件类型判断动作是否执行。如果条件符合,则执行动作,否则读入下一行数据;
4) 当所有的行匹配结束,执行END条件。
[root@master ~]# echo -e "A line 1 \nA line 2" | awk 'BEGIN{print "BEGIN"} {print} END{print "END"}' BEGIN A line 1 A line 2 END
6、使用正则表达式:
想查看学生“Wangwu”的成绩:
[root@master ~]# awk '/Wangwu/{print}' students.txt 3 Wangwu 93 99 83 91.66
使用df命令查看分区使用情况时,只返回真正的系统分区的使用状况:
[root@master ~]# df -h | awk '$1 ~ /sda[0-9]/ {print $1,$5}' /dev/sda2 20% /dev/sda1 71%
7、awk的内置变量
awk内置变量 | 作 用 |
$0 | 代表目前awk所读入的整行数据。 |
$n | 代表目前读入行的第n个字段(第n列)。 |
NF | 当前行拥有的字段(列)总数。 |
NR | 当前awk所处理的行,是总数据的第几行。 |
FS | 用户自定义分隔符。awk默认的分隔符是任何空格。 |
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
FNR | 当前文件中的当前记录数 |
RS | 输入记录分隔符(默认为换行符) |
ORS | 输出记录分隔符(默认为换行符) |
[root@master ~]# echo -e "line1 f1 f2\nline2 f3 f4\nline3 f4 f5" | awk '{print "Line No: "NR,"No of fields: " NF,"$0: "$0, "$1: "$1,"$2: "$2,"$3: "$3 }' Line No: 1 No of fields: 3 $0: line1 f1 f2 $1: line1 $2: f1 $3: f2 Line No: 2 No of fields: 3 $0: line2 f3 f4 $1: line2 $2: f3 $3: f4 Line No: 3 No of fields: 3 $0: line3 f4 f5 $1: line3 $2: f4 $3: f5
使用分隔符:
[root@master ~]# cat /etc/passwd | awk -F ':' '{printf $1"\t"$3"\n"}' 或 [root@master ~]# cat /etc/passwd | awk 'BEGIN{FS=":"} {printf $1"\t"$3"\n"}'
8、awk流程控制:
求学生的MySQL成绩的总和:
[root@master ~]# awk 'NR==2{s1=$3} NR==3{s2=$3} NR==4{s3=$3;total=s1+s2+s3;print "Total is:" total}' students.txt Total is:275 或者 [root@master ~]# awk 'NR>1{s+=$3}END{print "Total is:" s}' students.txt Total is:275
注意区分:
[root@master ~]# awk 'NR==2{s1=$3} NR==3{s2=$3} NR==4{s3=$3} {total=s1+s2+s3;print "Total is:" total}' students.txt Total is:0 Total is:86 Total is:182 Total is:275
如果MySQL成绩大于90,则输出“is a good student!”:
[root@master ~]# awk '{if(NR>=2 && NR<=4){if($3>90){print $2,"is a good student!"}}}' students.txt Sunsi is a good student! Wangwu is a good student! 或者 [root@master ~]# awk 'NR>=2 && NR<=4 && $3>90{print $2,"is a good student!"}' students.txt Sunsi is a good student! Wangwu is a good student!
第一个if条件,判断行数在2(包含)到4(包含)之间;
第二个if条件,判断第三列(即MySQL列)是否大于90;
print语句中的“,”会在标准输出中输入一个空格。
注意事项:
多个“条件{动作}”可以用空格分隔,也可以用回车分隔;
在一个动作中,如果需要执行多个命令,需要用“;”分隔,或者用回车分隔;
在awk中,变量的赋值和调用都不需要加入“$”;
条件判断中如果判断两个值是否相同,使用"==";
当使用不带参数的print时,它就打印当前行的内容。当print的参数是以逗号做分隔符时,打印的结果以空格作为定界符;
在awk的print语句块中双引号是被当作拼接符使用;
在进行算术运算时,所有操作数自动转为数值,所有非数值都变为0。
[root@master ~]# echo | awk 'a="b" {print a++, ++a}' 0 2
9、awk函数
定义方法如下:
function 函数名(参数列表){ 函数体 }
实例,在第二列和第三列中间加“ ||| ”:
[root@master ~]# awk 'function test(a,b){print a,"|||",b} test($2, $3)' students.txt Name ||| MySQL Lisan ||| 86 Sunsi ||| 96 Wangwu ||| 93
10、awk中调用脚本
创建一个.awk结尾的文件:
[root@master ~]# cat pass.awk BEGIN{print "Hello Boys"} {print $1,$2,$3} END{print "Bye Boys"}
通过-f选项调用:
[root@master ~]# awk -f pass.awk students.txt Hello Boys ID Name MySQL 1 Lisan 86 2 Sunsi 96 3 Wangwu 93 Bye Boys
11、用awk按列求和:
用到的示例文件内容如下:
[root@master ~]# cat file1 a 1 a 3 a 4 c 6
求第二列的和:
[root@master ~]# awk '{s+=$2}END{print s}' file1 14
12、用awk进行分组求和:
用到的示例文件内容如下:
[root@master ~]# cat file2 a 1 2 a 2 3 a 2 5 c 4 6
以第一列为变量名,将相同第一列的第二列数据进行累加,打印出和:
[root@master ~]# awk '{s[$1]+=$2} END{for(i in s){print i,s[i]}}' file2 a 5 c 4
以第一列、第二列为变量名,将相同第一列、第二列的第三列的数据进行累加,打印出和:
[root@master ~]# awk '{s[$1,$2]+=$3} END{for(i in s){print i,s[i]}}' file2 c4 6 a1 2 a2 8
以第一列为变量名,打印出第二列和第三列的数据和:
[root@master ~]# awk '{s[$1]+=$2; a[$1]+=$3} END{for(i in s){print i,s[i],a[i]}}' file2 a 5 10 c 4 6
13、将外部变量传递给awk:
指定-v参数,可以将环境变量传递给awk使用:
[root@master ~]# var=100 [root@master ~]# echo | awk -v VARIABLE=$var '{print VARIABLE}' 100
14、awk高级输入输出
awk中next语句使用:逐行匹配,如果遇到next,就会跳过当前行,进行下一次匹配。next语句一般用于合并多行:
[root@master ~]# awk '$2~/Name/{T=$2;next}{print T"\t"$2}' students.txt Name Lisan Name Sunsi Name Wangwu