AWK

GNU awk

全称:Aho,Weiberger,Kernighan,是三个作者的名字,所以简称为awk

awk:报告生成器,主要用来格式化文本输出的,它能够实现在处理文本文件时对文档中的字段有条件的显示,而且将显示的结果用非常美观的文本形式给予输出。我们所用的awk其实就是gawk,他是一个符号链接指向gawk的。

gawk – pattern scanning and processing language:模式扫描及处理语言

  awk其实就是一个解释器,是一个编程语言的解释器,从本质上来讲他也是一个编程语言,支持条件判断、数组、循环等各种各样一个编程语言当中几乎所有的功能。因此我们又可以把gawk称为一个脚本语言解释器,他所支持的是一个单独的脚本编程语言的功能。和bash编程语言一样,也是过程式编程语言。另外gawk也有自己内置的变量,允许用户自定义变量。

awk的基本用法:

awk [options] 'program' FILE ...
    paogram的组成:PATTERN{ACTION STAEMRNTS(动作语句)}:可以有多个语句,语句之间用分号分割。

    选项:
        -F:指明输入时用到的字段分隔符:从文件中读取数据时以什么当作分割符
        -v var=varlaue:用于实现自定义变量:

awk常用的输出命令:

1、print

print item1,item2,...
    要点:
        (1)逗号分隔符:
        (2)输出的各item可以是字符串,也可以是数值,也可以是当前记录的字段,变量或awk的表达式
        (3)如省略item,相当于print $0(打印整行)

2、变量

内建变量
        FS:input field seperator:输入字段分隔符,默认为空白字符
        OFS:output field seperator:输出字段分隔符,默认为空白字符
        RS:input record seperator:输入时的换行符
        ORS:output record seperator:输出时的换行符
        NF:number of field:每一行的字段数量
            {print NF},{print $NF}
        NR:num of record:行数
        FNR:各文件分别计数:行数
        FILENAME:当前文件名
        ARGC:命令行参数的个数
        ARGV:是一个数组,保存的是命令行所给定的各参数
自定义变量   
        (1)-v var=value
            变量名区分字符大小写:
        (2)在program中直接定义

3、printf

格式化输出:printf FORMAT,item1,item2,...
        (1)FORMAT必须给出
        (2)不会自动换行,需要显示给出换行控制符,\n
        (3)FORMAT中需要分别为后面的每个intem指定一个格式化符号
            格式符:
                %c:显示字符的ASCII码
                %d,%i:显示十进制整数
                %e,$E:科学计数法数值显示
                %f:显示为浮点数
                %g,%G:以科学计数法或浮点形式显示数值
                %s:显示字符串
                %u:无符号整数
                %%:显示%号自身 
            修饰符:
                #[.#]:第一个数字控制显示的宽度:第二个#显示小数点后的精度:
                -:左对齐
                +:显示数值的符号

4、操作符

算术操作符:
        x+y,x-y,x*y,x/y,x^y,x%y
        -x
        +x:转换为数值:
    字符串操作符:没有符号的操作符,字符串连接的意思
赋值操作符:
        =,+=,-=,*=,/=,%=,^=
        ++,--
比较操作符:
        >,>=,<,<=,!=,==
模式匹配符:
        ~:是否匹配
        !~:是否不匹配
逻辑操作符:
        &&,||,!
函数调用:
        function_name(argu1,argu2,...)
条件表达式:
        selector?if-true-expression:if-fales-expressiion
        示例:格式化显示/etc/passwd文件中用户名是普通用户还是系统用户还是管理员
        awk -F: '{$3>=500?usertype="Common User":usertype="Sysadmin or Sysuser";printf "%15s:%-s\n",$1,usertype}' /etc/passwd

5、pattern

(1)empty:空模式,匹配每一行
(2)/regular expression/:仅处理能够被此处模式匹配到的行
(3)relational expression:关系表达式:结果有“真”有“假”,结果为“真”才会被处理;
    真:结果为非0值为真,非空字符串也为真
(4)line ranges:行范围,指明起始行,指明结束行
    startline,endline:/pat1/,/pat2/
    注意:不支持直接给出数字的格式,须使用如下格式
    示例:显示/etc/passwd中第2行到第10行的用户名
    ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
(5)BENGIN/END模式
    BENGIN{}:仅在开始处理文件中的文本之前执行一次:
    END{}:仅在文本处理完成之后执行一次

6、常用的action

(1)Expressions:表达式
(2)Control statements:控制语句,if,while,for等
(3)Compound statemens:组合语句
(4)input statemens:输入语句
(5)output statemens:输出语句

7、控制语句

if(condition) {statmens}
if(condition) {statmens} else {statemens}
while(condition) {statmens}
do {statmens} while(condition)
for(expr1;expr2;expr3) {statemens}
break
continue
delete arrar[index]
delete array
exit
{ statements}

控制语句说明
    (1)if-else
    语法:if(condition) statement [else statement]
    ~]# awk -F: '{if($3>=500) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd
    ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
    示例:显示/etc/fstab文件中字段数大于5的行
    ~]# awk '{if(NF>5) print $0}' /etc/fstab
    示例:显示当前使用空间大于20的设备名称
    ~]# df -h | awk -F[%] '/^\/dev/{print $1}' |awk '{if($NF>=20) print $1}'
    使用场景:对awk取得的整行或某个字段做条件判断
    (2)while循环
    语法:while(condition) statemnt
        条件为真进入循环:条件为假退出循环
    使用场景:对一行内的多个字段逐一类似处理时使用:对数组中的各元素逐一处理时使用:

    ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i); i++}}' /etc/grub2.cfg
    ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i); i++}}' /etc/grub2.cfg
    (3)do-while循环
    语法:do statement while(condition)
        意义:至少执行一次循环体
    (4)for循环
    语法:for(expr1;expr2;expr3) statement
        for(variable assignment;conditiion;iteration process) {for-body}
        ~]# awk '/^[[:space:]]*llinux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
        特殊用法:
            能够遍历数组中的元素:
            语法:for(var in array) {for-body}
    (5)switch语句
    语法:switch(expression) {case VALUE1 or /REGEXP/: statement;case VALUE2 or /REGEXP2/: statement;...;default: statement}
    (6)break和continue
        break [n]
        continue
    (7)next
        提前结束对本行的处理而直接进入下一行
    示例:显示ID号为偶数的用户
    ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd

8、array

关联数组:array[index-expression]
    index-expreesion
        (1)可使用任意字符串;字符串要使用双引号
        (2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
            如要判断数组中是否存在某元素,要使用“index in array”格式进行
            weekdays["mon"]="Monday"
            如要遍历数组中的每个元素,要使用for循环
                for(var in  array) {for-boby}
                ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="tuesday";for(i in weekdays) {print weekdays[i]}}'
            注意:var会遍历array的每个索引
                示例:显示各端口的状态次数
                ~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'
                示例:显示每个ip地址访问httpd服务的次数
                ~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
            练习1:统计/etc/fstab文件中每个文件系统类型出现的次数
                ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
            练习2:统计指定文件中每个单词出现的次数;
                ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab

9、函数

(1)内置函数
    数值处理
        rand():返回0和1之间一个随机数
    字符串处理
        length([s]):返回指定字符串的长度
        sub(r,s,[t]):以r表示的模式来查找t所表示的字符串中的匹配的内容,并将其第一次出现替换为s所表示的内容
        gsub(r,s,[t]):以r表示的模式来查找t所表示的字符串中的匹配的内容,并将其所有出现均替换为s所表示的内容
        split(s,a,[r]):以r为分割符切割字符s,并将切割后的结果保存至a所表示的数组中
        ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}'
(2)自定义函数
练习:

显示/etc/fstab文件后五行的第2和第4个字段

]# tail -5 /etc/fstab  |awk '{print $2,$4}'

显示/etc/fstab文件后五行的第2和第4个字段,并且在输出的行首显示“ali”字符,在行尾显示数字“1”。

]# tail -5 /etc/fstab |awk '{print "ali",$2,$4,1}'

显示/etc/passwd文件中的第1个字段,要求awk内建变量输入分割符为冒号

]# awk -v FS=':' '{print $1}' /etc/passwd

使用冒号为分割符显示/etc/passwd文件中的用户名

]# awk -F: '{print $1}' /etc/passwd

使用输入分隔符为冒号和输出分隔符为冒号显示/etc/passwd文件的第1,3,7字段(以冒号为分割符显示/etc/passwd中用户名,UID,shell类型)

]# awk -F':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd

以空格为属入换行符显示/etc/passwd文件

]# awk -v RS=' ' '{print }' /etc/passwd

显示/etc/fstab文件中每行的字段数

]# awk '{print NF}' /etc/fstab

显示/etc/passwd文件中每行的最后一个字段

]# cat /etc/passwd |awk -F':' '{print $NF}'

分别显示/etc/fstab和/etc/issue文件的行数

]# awk '{print FNR}' /etc/fstab /etc/issue

格式化显示/etc/passwd文件中每行的用户名,UID,shell类型,要求对应显示username,uid,shelltype

]# awk -F: '{printf "username: %s, uid: %d, shelltype: %s \n",$1,$3,$7}' /etc/passwd

格式化显示/etc/passwd文件中每行的用户名,UID,shell类型,要求对应显示username,uid,shelltype,并且格式输出宽度为15个字符,左对齐。

]# awk -F: '{printf "username: %-15s, uid: %-15d, shelltype: %-15s \n",$1,$3,$7}' /etc/passwd

显示/etc/fstab文件中以UUID开头的行

]# awk '/^UUID/{print }' /etc/fstab

显示/etc/fstab文件中不以UUID开头的行

]# awk '!/^UUID/{print }' /etc/fstab

显示UID大于500的用户名和UID

]# awk -F: '$3>=500{print $1,$3}' /etc/passwd
]# awk -F: '{if($3>=500)print $1,$3}' /etc/passwd

显示shell类型为bash的用户

]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd

原创文章,作者:M20-1马星,如若转载,请注明出处:http://www.178linux.com/48725