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