AWK介绍

Linux 文本处理工具三剑客:grep、sed、awk。其中grep是一种文本过滤工具;sed是文本行编辑器,而awk是一种报表生成器,就是对文件进行格式化处理的,但这里的格式化不是文件系统的格式化,而是对文件内容进行各种“排版”,进而格式化显示;在Linux之上我们使用的是GNU awk 简称gawk,并且gawk就是awk的链接文件,因此系统上使用的awk和gawk是一样的。gawk是一种过程式编程语言。gawk还支持条件判断、数组、循环等编程语言中所有可以使用的功能,因此还可以把gawk称为一种脚本语言解释器。

(1)用法格式,选项

基本格式:awk [options] 'program' file…

      program:PATTERN{ACTION STATEMENT;..},通常是在单引号和双引号中;

      program:编程语言;

      PARTTERN:模式;部分决定动作语句何时触发及触发事件(BEGIN,END)

      ACTION STATEMENT:动作语句,可以由多个语句组成,各语句之间使用分号分隔:如print,printf

options(选项):

      -F:指明输入时用到的字段分隔符;

      -v var=value: 自定义变量

分割符、域和记录

      awk执行时,由分隔符分隔的字段(域);标记$1,$2..$n称为域标识。$0为所有域,注意:和shell中变量$符含义不同

      文件的每一行称为记录

      省略action,则默认执行print $0 的操作。

(2)awk工作原理

原理:

awk在处理文本时也是一次读取一行文本,然后根据输入分隔符(默认为空格字符)进行切片,切成n个片段,然后将每一片都赋予awk内部的一个变量当中进行保存,这些变量名为$1,$2,$3…等等一直到最后一个,awk就可以对这些片段进行单独处理,比如显示某一段,特定段,甚至可以对某些片段进行额外的的加工处理,比如计数、运算等。

具体工作原理如下:

    第一步:执行BEGIN{action;… }语句块中的语句;  

    第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

    第三步:当读至输入流末尾时,执行END{action;…}语句块;

        BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化打印输出 表格的表头等语句通常可以写在BEGIN语句块中

        END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块

        pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

使用实例:

[root@wlm ~]# awk 'BEGIN{print "Hello,awk!"}'
Hello,awk!    # BEGIN操作是第一步,不需要对文件进行操作
[root@wlm ~]# awk 'END{print "Bye,awk!"}' /etc/passwd
Bye,awk!      # END的操作实在文本处理之后
[root@wlm ~]# awk -F: 'BEGIN{print "Hello,awk!"}''/root/{print $1,$2}''END{print "Bye,awk!"}' /etc/passwd
Hello,awk!
root x
operator x
Bye,awk!
# 首先是进行BEGIN操作;再查找含有root字符的行,打印第一列和第二列;最后执行END操作


用法说明:

1、print:输出命令

要点:

     (1) 逗号分隔符;

     (2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式;

     (3) 如省略item,相当于print $0; 

使用实例:

[root@wlm ~]# awk -F: '/root/{print $1,$3}' /etc/passwd
root 0
operator 11
# 查找含有root字符的行,以:为分隔符,显示第一列和第三列
[root@wlm ~]# awk -F: '/root/{print "UserName:",$1,"UID:",$3}' /etc/passwd
UserName: root UID: 0
UserName: operator UID: 11
# print里也可以使用字符串
[root@wlm ~]# awk -F: '/root/{print}' /etc/passwd    #如省略item,相当于print $0
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@wlm ~]# awk -F: '/root/{print $1"\n"$3}' /etc/passwd    #加入换行符,必须用""
root
0
operator
11
[root@wlm ~]# awk -F: '/root/{print $1"\t"$3}' /etc/passwd    #制表符
root	0
operator	11
[root@wlm ~]# awk -F: '/root/{print "awk"}' /etc/passwd    #每一行执行时要打印的
awk
awk

    

2、AWK变量:内在变量和自定义变量

2.1 内建变量

内置变量

    FS:输入字段分隔符,默认为空白字符

         awk -v FS=':' '{print $1,$3,$7}’ /etc/passwd

         awk -F: '{print $1,$3,$7}’ /etc/passwd

    OFS:输出字段分隔符,默认为空白字符

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

    RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效

         awk -v RS=' ' ‘{print }’ /etc/passwd

    ORS:输出记录分隔符,输出时用指定符号代替换行符

         awk -v RS=' ' -v ORS='###'‘{print }’ /etc/passwd

    NF:字段数量

         awk -F:‘{print NF}’ /etc/fstab, 引用内置变量不用$

         awk -F: '{print $(NF-1)}' /etc/passwd

    NR:行号

         awk '{print NR}' /etc/fstab; awk END'{print NR}' /etc/fstab

    FNR:各文件分别计数,行号

         awk '{print FNR}' /etc/fstab /etc/inittab

    FILENAME:当前文件名

        awk '{print FILENAME}’ /etc/fstab

    ARGC:命令行参数的个数

        awk '{print ARGC}’ /etc/fstab /etc/inittab

        awk ‘BEGIN {print ARGC}’ /etc/fstab /etc/inittab

    ARGV:数组,保存的是命令行所给定的各参数

        awk ‘BEGIN {print ARGV[0]}’ /etc/fstab /etc/inittab

        awk ‘BEGIN {print ARGV[1]}’ /etc/fstab /etc/inittab

 

使用实例:

[root@wlm ~]# awk -F: -v OFS="+++" '/^user/{print $1,$3,$7}' /etc/passwd
user1+++1003+++/bin/bash
user2+++1004+++/bin/bash
user3+++1005+++/bin/bash
#以:为输入分隔符,+++为输出分隔符,打印以user开头的行的第1,3,7列
[root@wlm ~]# awk -F: '{print NF}' /etc/passwd
7
7
# 以:为分隔符,显示最后一列的序列号
[root@wlm ~]# awk -F: '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
# 以:分隔符,显示最后一列
[root@wlm ~]# awk '{print NR}' /etc/passwd
1
2
# 遍历每一行时候显示序列号
[root@wlm ~]# awk '{print FNR}' /etc/fstab /etc/resolv.conf 
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
# 遍历两个文件,分别显示序列号,如果是NR,则第二个文件在第一个文件基础上显示序列号
[root@wlm ~]# awk END'{print NR}' /etc/fstab 
12
# 显示最后一行的行号
[root@wlm ~]# awk END'{print FNR}' /etc/fstab /etc/resolv.conf 
3
# 显示最后一个文件的序列号
[root@wlm ~]# awk '{print FILENAME}' /etc/fstab 
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
/etc/fstab
# 显示文件的基名
[root@wlm ~]# awk '{print ARGC}' /etc/fstab /etc/inittab 
3
3
3
3
3
3
3
# 显示参数个数,且遍历的每一行都会显示
[root@wlm ~]# awk 'BEGIN{print ARGC}' /etc/fstab /etc/resolv.conf 
3
# 加上BEGIN,只显示一次参数个数
[root@wlm ~]# awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/inittab 
awk
# 显示数字的第一个值
[root@wlm ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/inittab 
/etc/inittab

2.2 自定义变量

    (1) -v var=value

    变量名区分字符大小写;

    (2) 在program中直接定义

使用实例:

[root@wlm ~]# awk -v i="I've seen the world" '{print i}' /etc/fstab
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
I've seen the world
[root@wlm ~]# awk -v i="I've seen the world" 'BEGIN{print i}'
I've seen the world
[root@wlm ~]# awk 'BEGIN{i="I have seen the world";print i}' /etc/passwd
I have seen the world

3、printf命令

格式化输出:printf FORMAT, item1, item2, ...

     (1) FORMAT必须给出; 

     (2) 不会自动换行,需要显式给出换行控制符,\n

     (3) FORMAT中需要分别为后面的每个item指定一个格式化符号;    

格式符:

     %c: 显示字符的ASCII码;

     %d, %i: 显示十进制整数;

     %e, %E: 科学计数法数值显示;

     %f:显示为浮点数;

     %g, %G:以科学计数法或浮点形式显示数值;

     %s:显示字符串;

     %u:无符号整数;

     %%: 显示%自身;

修饰符:

     #[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度;

     %3.1f

     -: 左对齐

     +:显示数值的符号

使用实例:

[root@wlm ~]# awk -F: '{printf "%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-bus-proxysystemd-networkdbuspolkitdabrtunboundtsscolordusbmuxdgeocluesaslauthlibstoragemgmtrpcrtkitchronyradvdqemuntprpcusernfsnobodyavahi-autoipdsetroubleshootsssdpulsegdmgnome-initial-setupsshdavahipostfixtcpdumpdtshadoopwlmuser1user2user3user4user5user6user7user8user9user10
# 默认是不会换行的
[root@wlm ~]# awk -F: '{printf "%s\n",$1}' /etc/passwd    # 加\n,主动换行
root
bin
daemon
adm
[root@wlm ~]# awk -F: '{printf "Username:%s UID:%d\n",$1,$3}' /etc/passwd
Username:root UID:0
Username:bin UID:1
Username:daemon UID:2
Username:adm UID:3
# 添加字符串.
[root@wlm ~]# awk -F: '{printf "Username:%15s UID:%d\n",$1,$3}' /etc/passwd
Username:           root UID:0
Username:            bin UID:1
Username:         daemon UID:2
Username:            adm UID:3
Username:             lp UID:4
Username:           sync UID:5
Username:       shutdown UID:6
Username:           halt UID:7
# 添加修饰符,显示宽度为15字符,默认为右对齐
[root@wlm ~]# awk -F: '{printf "Username:%-15s UID:%d\n",$1,$3}' /etc/passwd
Username:root            UID:0
Username:bin             UID:1
Username:daemon          UID:2
Username:adm             UID:3
Username:lp              UID:4
# 左对齐显示

4、操作符

算数操作符:

       x+y, x-y, x*y, x/y, x^y(x的y次方), x%y

       -x: 转换为负数;

       +x: 转换为数值;

字符串操作符:没有符号的操作符,字符串连接;

赋值操作符:

       =, +=, -=, *=, /=, %=, ^=

       ++, —

比较操作符:

       >, >=, <, <=, !=, ==

模式匹配符:

      ~:左边是否和右边匹配包含

     !~:是否不匹配

         cat /etc/passwd |awk'$0 ~ /root/' |wc -l

         cat /etc/passwd |awk'$0 !~ /root/' |wc -l

逻辑操作符:&&,||,!

示例:

     awk–F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd

     awk -F: '$3 ==0 || $3>=1000 {print $1}' /etc/passwd

     awk -F: ‘!($3==0){print $1}' /etc/passwd

     awk -F: '!($3>=500) {print $3}}' /etc/passwd

函数调用:

      function_name(argu1, argu2, …)

条件表达式:

      selector?if-true-expression:if-false-expression

使用实例:

# 显示用户的UID如果大等于1000则为普通用户,否则为管理员或系统用户,并定义格式输出
[root@wlm ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf"%15s:%-s\n",$1,usertype}' /etc/passwd
           root:Sysadmin or SysUser
            bin:Sysadmin or SysUser
         daemon:Sysadmin or SysUser
            adm:Sysadmin or SysUser
             lp:Sysadmin or SysUser
           sync:Sysadmin or SysUser
       shutdown:Sysadmin or SysUser
           halt:Sysadmin or SysUser
           mail:Sysadmin or SysUser
       operator:Sysadmin or SysUser
          games:Sysadmin or SysUser
            ftp:Sysadmin or SysUser
         nobody:Sysadmin or SysUser
systemd-bus-proxy:Sysadmin or SysUser
systemd-network:Sysadmin or SysUser
           dbus:Sysadmin or SysUser
        polkitd:Sysadmin or SysUser
           abrt:Sysadmin or SysUser
        unbound:Sysadmin or SysUser
            tss:Sysadmin or SysUser
         colord:Sysadmin or SysUser
        usbmuxd:Sysadmin or SysUser
        geoclue:Sysadmin or SysUser
       saslauth:Sysadmin or SysUser
 libstoragemgmt:Sysadmin or SysUser
            rpc:Sysadmin or SysUser
          rtkit:Sysadmin or SysUser
         chrony:Sysadmin or SysUser
          radvd:Sysadmin or SysUser
           qemu:Sysadmin or SysUser
            ntp:Sysadmin or SysUser
        rpcuser:Sysadmin or SysUser
      nfsnobody:Common User
  avahi-autoipd:Sysadmin or SysUser
 setroubleshoot:Sysadmin or SysUser
           sssd:Sysadmin or SysUser
          pulse:Sysadmin or SysUser
            gdm:Sysadmin or SysUser
gnome-initial-setup:Sysadmin or SysUser
           sshd:Sysadmin or SysUser
          avahi:Sysadmin or SysUser
        postfix:Sysadmin or SysUser
        tcpdump:Sysadmin or SysUser
            dts:Common User
         hadoop:Common User
            wlm:Common User
          user1:Common User

5、PATTERN

根据pattern条件,过滤匹配的行,再做处理

(1)如果未指定:空模式,匹配每一行

(2)/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来;

       awk'/^UUID/{print $1}' /etc/fstab

       awk'!/^UUID/{print $1}' /etc/fstab

(3)relational expression: 关系表达式;

   结果有“真”有“假”;结果为“真”才会被处理;

       真:结果为非0值,非空字符串;

       假:结果为空字符串;

(4)line ranges:行范围

     startline,endline:/pat1/,/pat2/不支持直接给出数字格式

        awk -F: '/^root/,/^nobody/{print $1}' /etc/passwd

        awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd

(5)BEGIN/END 模式

        BEGIN{}: 仅在开始处理文件中的文本之前执行一次

        END{}:仅在文本处理完成之后执行一次

使用实例:

[root@wlm ~]# awk '!/^UUID/{print $1}' /etc/fstab 
            # 显示不是以UUID开头的行,并打印第一列
#
#
#
#
#
#
#
/dev/mapper/centos-root
/dev/mapper/centos-home
/dev/mapper/centos-swap
[root@wlm ~]# awk '/^UUID/{print $1}' /etc/fstab 
UUID=3dc2559c-29f0-4e22-83b7-d979e6f60504
# 显示以UUID开头的行
[root@wlm ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534    
# 关系表达式,也可以成为比较表达式,条件为真,才会被处理。题目表示,如果UID大于等于1000,则打印用户名和UID
dts 1000
hadoop 1001
[root@wlm ~]# awk -F: '$NF=="/bin/bash"{print $1,$3}' /etc/passwd
root 0         # 表示最后一个片段等于/bin/bash,然后符合的打印 用户名和UID
dts 1000
hadoop 1001
wlm 1002
[root@wlm ~]# awk -F: '$NF~/bash/ {print $1,$NF}' /etc/passwd
root /bin/bash    # 表示左边的值能够被右边的模式所匹配
dts /bin/bash
hadoop /bin/bash
wlm /bin/bash
[root@wlm ~]# awk -F: '/^root/,/^mail/{print $1}' /etc/passwd
root    # 表示第一次被/^root/模式匹配到的行开始,到第一次被/^mail/模式匹配到的行结束
bin
daemon
adm
lp
sync
shutdown
halt
mail
[root@wlm ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
bin        # 表示第二行到第十行,打印用户名
daemon
adm
lp
sync
shutdown
halt
mail
operator
[root@wlm ~]# awk -F: 'BEGIN{print "   username   uid   \n----------------------"}'
   username   uid   
----------------------    # 打印表头
[root@wlm ~]# awk -F: 'BEGIN{print "           username   uid   \n--------------------------"}{printf "%18s %3d\n",$1,$3}' /etc/passwd
           username   uid   
--------------------------
              root   0
               bin   1
            daemon   2
               adm   3
                lp   4

6、常用的action

    (1)Expressions:           算术,比较表达式等

    (2)Control statements:  控制语句 if, while等

    (3)Compound statements: 组合语句

    (4)input statements:     输入语句

    (5)output statements:    输出语句 print等

7、控制语句

     if(condition) {statments} 

     if(condition) {statments} else {statements}

     while(conditon) {statments}

     do {statements} while(condition)

     for(expr1;expr2;expr3) {statements}

     break

     continue

     delete array[index]

     delete array

     exit 

     { statements }

7.1 if-else

语法:if(condition) statement [else statement]

事例:

~]# awk -F: '{if($3>=1000) {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

~]# awk '{if(NF>5) print $0}' /etc/fstab

~]# df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print $1}'

使用场景:对awk取得的整行或某个字段做条件判断;

使用实例:

[root@wlm ~]# awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd # 单分支语句
[root@wlm ~]# awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or Sysuser: %s\n",$1}}' /etc/passwd   
root or Sysuser: root    # 双分支语句,一定注意语法书写格式!!!
root or Sysuser: bin
root or Sysuser: daemon
root or Sysuser: adm
root or Sysuser: lp
[root@wlm ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd   # 对某个字段做条件判断
[root@wlm ~]# awk '{if(NF>5) print $0}' /etc/fstab  # 如果字段大于5,就打印
[root@wlm ~]# 
[root@wlm ~]# 
[root@wlm ~]# df -h | awk -F[%] '{print $1}'     # 以%为分隔符,取第一字段
文件系统                 容量  已用  可用 已用
/dev/mapper/centos-root   50G   14G   37G   27
devtmpfs                 478M     0  478M    0
tmpfs                    493M   88K  493M    1
tmpfs                    493M  7.1M  486M    2
tmpfs                    493M     0  493M    0
/dev/mapper/centos-home   68G   33M   68G    1
/dev/sda1                497M  158M  340M   32
tmpfs                     99M   20K   99M    1
/dev/sr0                 4.1G  4.1G     0  100
[root@wlm ~]# df -h | awk -F[%] '{print $1}' | awk '{print $NF}'
已用    # 再取最后一个字段
27
0
1
2
0
1
32
1
100
[root@wlm ~]# df -h | awk -F[%] '/\/dev/{print $1}' | awk '{print $NF}'
27     # 模式匹配,匹配 以/dev开头的行,注意这里要对/ 转义,模式匹配一定要写在 “/ /”中
0
1
1
32
100
[root@wlm ~]# df -h | awk -F[%] '/\/dev/{print $1}' | awk '{if($NF>=20) print $NF}'
27    # 如果利用率大于等于20,就打印第一字段
32
100

7.2 while循环

语法:while(condition) statement

条件“真”,进入循环;条件“假”,退出循环;

使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用;

事例:

~]# 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

使用实例:

[root@wlm ~]# awk '/[[:space:]]*linux16/{print}' /etc/grub2.cfg  # 取文件模式所匹配的行
	linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=zh_CN.UTF-8
	linux16 /vmlinuz-0-rescue-32980c4fdaf54a9fad135a028895168b root=/dev/mapper/centos-root ro crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet
[root@wlm ~]# awk '/[[:space:]]*linux16/{print NF}' /etc/grub2.cfg
10        # 所匹配行的字段数量
9
[root@wlm ~]# awk '/[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++ }}' /etc/grub2.cfg        
linux16 7         # 对每一行字段中包含的字符长度做统计。 这里用到了while循环,当i小于等于字段数量,是就执行打印这一字段,及字段长短,并且执行i++,注意循环体用{}括起来  
/vmlinuz-3.10.0-327.el7.x86_64 30
root=/dev/mapper/centos-root 28
ro 2
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
rhgb 4
quiet 5
LANG=zh_CN.UTF-8 16
linux16 7
/vmlinuz-0-rescue-32980c4fdaf54a9fad135a028895168b 50
root=/dev/mapper/centos-root 28
ro 2
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
rhgb 4
quiet 5
[root@wlm ~]# awk '/[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)};i++}}' /etc/grub2.cfg
linux16 7    # 在上题的基础之上嵌套了一个if语句,表示如果字符长度大于7才打印,注意这里的{}表示的意义,最外面一层是整个的处理语句,倒数第二层表示循环体,最里面的表示if语句的执行动作,i++是while语句的,用分号分开
/vmlinuz-3.10.0-327.el7.x86_64 30
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
LANG=zh_CN.UTF-8 16
linux16 7
/vmlinuz-0-rescue-32980c4fdaf54a9fad135a028895168b 50
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21

7.3 do-while循环

语法:do statement while(condition)

意义:至少执行一次循环体

使用实例:

[root@wlm ~]# awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
5050

7.4 for循环

语法:for(expr1;expr2;expr3) statement

for(variable assignment;condition;iteration process) {for-body}

~]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg

特殊用法:

能够遍历数组中的元素;

语法:for(var in array) {for-body}

使用实例:

[root@wlm ~]# awk '/[[:space:]]*linux16/ {for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-327.el7.x86_64 30
root=/dev/mapper/centos-root 28
ro 2
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
rhgb 4
quiet 5
LANG=zh_CN.UTF-8 16
linux16 7
/vmlinuz-0-rescue-32980c4fdaf54a9fad135a028895168b 50
root=/dev/mapper/centos-root 28
ro 2
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
rhgb 4
quiet 5
[root@wlm ~]# awk '/[[:space:]]*linux16/ {for(i=1;i<=NF;i++) {if(length($i)>=7) print $i,length($i)}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-327.el7.x86_64 30
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21
LANG=zh_CN.UTF-8 16
linux16 7
/vmlinuz-0-rescue-32980c4fdaf54a9fad135a028895168b 50
root=/dev/mapper/centos-root 28
crashkernel=auto 16
rd.lvm.lv=centos/root 21
rd.lvm.lv=centos/swap 21

7.5 switch语句

语法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; ...; default: statement}

7.6 break和continue

break [n]

continue

7.7 next

提前结束对本行的处理而直接进入下一行;

~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd

使用实例:

[root@wlm ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
root 0    # 表示用户的ID号如果不为偶数,就提前终止这一行,直接进入下一行处理。
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
systemd-network 998
unbound 996
geoclue 994
libstoragemgmt 992
rpc 32
rtkit 172
ntp 38
nfsnobody 65534
avahi-autoipd 170
setroubleshoot 990
gdm 42
gnome-initial-setup 988
sshd 74
avahi 70
tcpdump 72
dts 1000
wlm 1002
user2 1004
user4 1006
user6 1008
user8 1010
user10 1012
[root@wlm ~]# awk -F: '{if($3%2==0) print $1,$3}' /etc/passwd
root 0    # 和上面表示的结果是相同的,但方法和意义不同
daemon 2
lp 4
shutdown 6
mail 8
games 12

8、array数组

关联数组:array[index-expression]

index-expression:

    (1) 可使用任意字符串;字符串要使用双引号;

    (2) 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”;

若要判断数组中是否存在某元素,要使用"index in array"格式进行;

    weekdays[mon]="Monday"

若要遍历数组中的每个元素,要使用for循环;

    for(var in array) {for-body}

事例:

~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'

注意:var会遍历array的每个索引;

    state["LISTEN"]++

    state["ESTABLISHED"]++

事例:

~]# netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) { print i,state[i]}}'

~]# awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log


练习1:统计/etc/fstab文件中每个文件系统类型出现的次数;

[root@wlm ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
xfs 1

练习2:统计指定文件中每个单词出现的次数;

[root@wlm ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab
Tue 1
man 1
and/or 1
maintained 1
xfs 3

9、函数

数值处理:

    rand():返回0和1之间一个随机数         

字符串处理:

    length([s]):返回指定字符串的长度

    sub(r,s,[t]):在t字符串搜索能够被r表示的模式所匹配的内容,并将第一个匹配的内容替换为s;

    gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容  

    split(s,array,[r]):以r为分隔符切割字符s,并将切割后的结果保存至array所表示的数组中