文本三剑客之AWK详解

文本三剑客之AWK

awk简介

            AWK是一种优良的文本处理工具。它不仅是 Linux中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

            awk是一个强大的文本分析工具,与grep(查找)、sed(编辑)一并称为“文本处理三剑客”。awk最强大的功能是对数据分析并生成报告。

            awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk是AWK的GNU版本。

工作原理

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

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

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

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

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

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

     分割符、域和记录 

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

            文件的每一行称为记录

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

步骤

  1. 执行BEGIN{action;…}
    BEGIN在输入之前执行,通常用来打印表头,变量初始化。

  2. 读取,执行pattern{action;…}
    默认执行{ print }

  3. 执行END{action;…}
    读取到打印结束后执行,通常用作分析结果,信息汇总

AWK语法基本格式:

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

选项[options]: 

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

        -v var=value: 自定义变量

        -f:调用awk脚本

program:pattern{action statements;..}

    语句之间用分号分割

pattern和action: 

pattern:部分决定动作语句何时触发及触发事件 BEGIN,END  (触发条件)

        action statements:对数据进行处理,放在{}内指明 print, printf  (对数据处理动作)

        program通常是被单引号或双引号中

知识点整理

1、print

 要点: 

(1) 逗号分隔符 

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

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

 示例: 

[root@centos7 ~]# tail -3 /etc/fstab #源文件
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print}'  
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# tail -3 /etc/fstab |awk '{print "wang"}'
wang
wang
wang

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $0}'
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2$4}'
/appdefaults
/bootdefaults
swapdefaults、

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2,$4}'
/app defaults
/boot defaults
swap defaults

[root@centos7 ~]# tail -3 /etc/fstab |awk '{print $2"\t"$4}'
/appdefaults
/bootdefaults
swapdefaults

2、变量

    2.1    内建命令

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

~]# awk -v FS=: '{print $1,FS,$3}' /etc/passwd
~]# awk -F":" '{print $1,$3}' /etc/passwd

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

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

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

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

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

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

    ARGC:命令行参数的个数

~]# awk -F: ‘{print NF}’ /etc/fstab,引用内置变量不用$ 
~]# awk -F:  '{print $(NF-1)}'  /etc/passwd

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

~]# [root@centos7 ~]# awk -F: '{print NF}' /etc/passwd 
7
7
~]# awk -F: '{print $(NF-1)}' /etc/passwd
/root
/bin

    NF:字段数量

~]#
 ~]# awk '{print NR}' /etc/fstab ; awk END'{print NR}' /etc/fstab

    NR:行号

~]# awk {print NR}' /etc/fstab /etc/fatab

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

~]#awk {print FNR}' /etc/fstab /etc/fatab

    FILENAME:当前文件名

~]# awk '{print FILENAME}' /etc/fstab 
/etc/fstab
/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
 ~]# awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/inittab
/etc/fstab
 ~]# awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/inittab
/etc/inittab
~]# awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/inittab #没有索引为空

2.2    自定义变量

    选项位置定义:-v var=hello

    在program中定义:awk ‘BEGIN{test=”hello”;print test}’

示例:

[root@centos7 ~]# awk -v test='hello gawk' '{print test}' /etc/fstab
hello gawk
hello gawk
hello gawk

root@centos7 ~]# awk -v test='hello gawk' 'BEGIN{print test}' /etc/fstab
hello gawk

[root@centos7 ~]# awk 'BEGIN{r=test="hello,gawk";print test}' /etc/fstab
hello,gawk

[root@centos7 ~]# awk -F: '{sex="male";print $1,sex,age;age=18}' /etc/passwd
root male
bin male 18
daemon male 18

[root@centos7 ~]# cat awk.txt #脚本实现awk输出
{print script,$1,$2}
[root@centos7 ~]# awk -F: -f awk.txt txt="awk" /etc/passwd   #-f调用swk脚本
 root x
 bin x

3、   printf命令

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

(1) 必须指定FORMAT 

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

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

    print不需要指定,printf需要指定format

    printf后面的字串需要使用双引号

    字串定义后的内容需要使用”,”分隔,后面直接跟Item1,item2….

    format用于指定后面的每个item的输出格式

    printf语句不会自动打印换行符\n

格式符

    %s: 显示字符串

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

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

    %f: 显示为浮点数

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

    %c: 显示字符的ASCII码

    %u: 无符号整数

    %%: 显示%号自身,相当于转义

修饰符

    N: 显示宽度

    -: 左对齐(默认为右对齐)

    +: 显示数值符号

示例:

[root@centos7 ~]# awk -F: '{printf"%s",$1}' /etc/passwd
rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdabrtlibstoragemgmtrpccolordsaslauthrtkitchronyqemutssusbmuxdgeocluerpcusernfsnobodyradvdsetroubleshootpulsegdmgnome-initial-s

[root@centos7 ~]# awk -F: '{printf"%s\n",$1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

[root@centos7 ~]# awk -F: '{printf"%-20s %10d\n",$1,$3}' /etc/passwd
root                          0
bin                           1
daemon                        2
adm                           3
lp                            4


[root@centos7 ~]# awk -F: '{printf"%-20.2s %10d\n",$1,$3}' /etc/passwd
ro 0
bi 1
da 2

[root@centos7 ~]# awk -F: '{print "username:%s\n",$1}' /etc/passwd
username:%s
 root
username:%s
 bin
 
 [root@centos7 ~]# 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
username:lp,UID:4
username:sync,UID:5

[root@centos7 ~]# awk -F: '{printf "username:%15s,UID:%d\n",$1,$3}' /etc/passwd
username:           root,UID:0
username:            bin,UID:1
username:         daemon,UID:2          #%15s 右对齐
username:            adm,UID:3

[root@centos7 ~]# awk -F: '{printf "username:%-15s,UID:%d\n",$1,$3}' /etc/passwd
username:root           ,UID:0
username:bin            ,UID:1
username:daemon         ,UID:2          #%-15s 左对齐
username:adm            ,UID:3

[root@centos7 ~]#  awk -F: '{printf "username:%-20s salary:%-10.2f shell:%s\n",$1,$3,$7}' /etc/passwd
username:root                 salary:0.00       shell:/bin/bash
username:bin                  salary:1.00       shell:/sbin/nologin
username:daemon               salary:2.00       shell:/sbin/nologin
username:adm                  salary:3.00       shell:/sbin/nologin
username:lp                   salary:4.00       shell:/sbin/nologin
username:sync                 salary:5.00       shell:/bin/sync
username:shutdown             salary:6.00       shell:/sbin/shutdown
username:halt                 salary:7.00       shell:/sbin/halt

4、操作符

    算数操作符

    x+y, x-y, x*y, x/y, x^y, x%y

    -x: 转换为负数 +x: 转换为数值 

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

    赋值操作符

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

    比较操作符

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

    模式匹配符

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

示例:

计算1加到100和为多少[root@centos7 ~]# echo {1..100}|tr " " + |bc
5050

[root@centos7 ~]# for ((sum=0,i=1;i<=100;i++));do let sum+=i;done;echo $sum
5050

[root@centos7 ~]# awk BEGIN'{for(i=1;i<=100;i++){sum+=i};print sum}'
5050

[root@centos7 ~]# awk BEGIN'{i=1;while (i<=100) {sum+=i;i++};print sum}'
5050
计算1加到100奇偶数和
#100以内偶奇数相加之和
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==0){continue};sum+=i};print sum}'
2500

#100以内偶数相加之和
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==1){continue};sum+=i};print sum}'
2550
#列出十以内的奇数
[root@centos6 ~]# seq 10 |awk '{if($1%2==0){next};print $1}'
1
3
5
7
9
#列出十以内的偶数
[root@centos6 ~]# seq 10 |awk '{if($1%2!=0){next};print $1}'
2
4
6
8
10

[root@centos7 ~]# awk -F: '$0 ~ /root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

root@centos7 ~]# awk -F: '$0 ~ /root/{print $1}' /etc/passwd
root
operator

[root@centos7 ~]# awk -F: '$0 ~ /^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

[root@centos7 ~]# awk -F: '$0 !~ /root/' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
.......

[root@centos7 ~]# awk -F: '$3==0' /etc/passwd
root:x:0:0:root:/root:/bin/bash

性能比较

[root@centos7 ~]# time(seq –s ”+” 1000000|bc)  #bc运算 
seq: invalid floating point argument: –s
Try 'seq --help' for more information.
real	0m0.004s
user	0m0.000s
sys	0m0.003s
[root@centos7 ~]# time(for ((i=0;i<=1000000;i++));do let total+=i;done;echo $total) #shell for运算
500000500000
real	0m7.236s
user	0m6.990s
sys	0m0.231s
[root@centos7 ~]#
[root@centos7 ~]# time(total=0;for i in {1..1000000};do total=$(($total+i));done;echo $total) #bash for运算
500000500000
real	0m7.150s
user	0m4.949s
sys	0m0.878s

[root@centos7 ~]# time (awk 'BEGIN{ total=0;for(i=0;i<=1000000;i++){total+=i;};print total;}') #awk运算
500000500000
real	0m0.217s
user	0m0.092s
sys	0m0.002s

逻辑操作符

    与&&,或||,非! : 

示例:

[root@centos7 ~]# awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
root
bin
daemon

[root@centos7 ~]# awk -F: '$3==0 || $3<=1000 {print $1}' /etc/passwd
root
bin
daemon

[root@centos7 ~]# awk -F: '!($3==0) {print $1}' /etc/passwd
bin
daemon
adm

[root@centos7 ~]# awk -F: '($3>=1000) {print $3}' /etc/passwd
65534
1000
1001
1002
4444

[root@centos7 ~]# awk -F: '!($3>=1000) {print $1}' /etc/passwd
root
bin
daemon
adm

[root@centos7 ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
nfsnobody 65534
li 1000
123 1001
12 1002
19 4444

函数调用: function_name(argu1, argu2, ...) 

条件表达式(三目表达式):

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

示例: 

[

[root@centos7 ~]# awk -F: '{$3>=1000?UserType="Common User":UserType="Sysasmin or sysUser";printf "%15s: %s\n",$1,UserType}' /etc/passwd
           root: Sysasmin or sysUser
            bin: Sysasmin or sysUser
         daemon: Sysasmin or sysUser
            adm: Sysasmin or sysUser
             lp: Sysasmin or sysUser
           sync: Sysasmin or sysUser
       shutdown: Sysasmin or sysUser
           halt: Sysasmin or sysUser
           mail: Sysasmin or sysUser
       operator: Sysasmin or sysUser
          games: Sysasmin or sysUser
            ftp: Sysasmin or sysUser
         nobody: Sysasmin or sysUser
systemd-network: Sysasmin or sysUser
           dbus: Sysasmin or sysUser
        polkitd: Sysasmin or sysUser
           abrt: Sysasmin or sysUser
 libstoragemgmt: Sysasmin or sysUser
            rpc: Sysasmin or sysUser
         colord: Sysasmin or sysUser
       saslauth: Sysasmin or sysUser
          rtkit: Sysasmin or sysUser
         chrony: Sysasmin or sysUser
           qemu: Sysasmin or sysUser
            tss: Sysasmin or sysUser
        usbmuxd: Sysasmin or sysUser
        geoclue: Sysasmin or sysUser
        rpcuser: Sysasmin or sysUser
      nfsnobody: Common User
          radvd: Sysasmin or sysUser
 setroubleshoot: Sysasmin or sysUser
          pulse: Sysasmin or sysUser
            gdm: Sysasmin or sysUser
gnome-initial-setup: Sysasmin or sysUser
           sshd: Sysasmin or sysUser
          avahi: Sysasmin or sysUser
        postfix: Sysasmin or sysUser
            ntp: Sysasmin or sysUser
        tcpdump: Sysasmin or sysUser
             li: Common User
         apache: Sysasmin or sysUser
            123: Common User
             12: Common User
             19: Common User

5、PATTERN

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

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

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

awk '/^UUID/{print $1}' /etc/fstab  仅处理匹配到的行

awk '!/^UUID/{print $1}' /etc/fstab 仅处理匹配到的行

(3) relational expression: 关系表达式,结果有“真”有“假”;结果为“真”才会被处理 ;

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

假:结果为空字符串或0值 

(4) line ranges:行范围

                startline,endline:/pat1/,/pat2/    处理 pattern1 到 pattern2 之间

                注意:不支持直接给出数字格式 

(5) BEGIN/END模式 

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

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

示例:

[root@centos7 ~]# df #处理前显示
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda2       20961280 3750180  17211100  18% /
devtmpfs          485144       0    485144   0% /dev
tmpfs             499848       0    499848   0% /dev/shm
tmpfs             499848   19832    480016   4% /run
tmpfs             499848       0    499848   0% /sys/fs/cgroup
/dev/sda5       20961280   32948  20928332   1% /app
/dev/sda1         201380  138984     62396  70% /boot
tmpfs              99972      36     99936   1% /run/user/0
/dev/sr0         8490330 8490330         0 100% /media

[root@centos7 ~]# df |grep /dev/sd |awk '{printf "DevName:%s Used:%s\n",$1,$5}'
#显示/dev/sd开头的行并对其输出显示进行优化
DevName:/dev/sda2 Used:18%
DevName:/dev/sda5 Used:1%
DevName:/dev/sda1 Used:70%

[root@centos7 ~]# df | awk '$0 ~ "/dev/sd" {printf "DevName:%-10s Used:%s\n",$1,$5}'
DevName:/dev/sda2  Used:18%
DevName:/dev/sda5  Used:1%
DevName:/dev/sda1  Used:70%

[root@centos7 ~]#  df |awk '$1~"^/dev/sd[[:lower:]][[:digit:]]\\>" && $5>=10 {printf "Filesystem: %-15s Used: %s\n",$1,$5}'
Filesystem: /dev/sda2       Used: 18%
Filesystem: /dev/sda1       Used: 70%

[root@centos7 ~]# df |awk '/\/dev\/sd[[:lower:]][[:digit:]]\>/{if($5>10){printf "DevName:%-10s Used:%s\n",$1,$5}}'
DevName:/dev/sda2  Used:18%
DevName:/dev/sda1  Used:70%

[root@centos7 ~]# awk -F: '$3<1000{print $1,$3 }' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
nobody 99
systemd-network 192
dbus 81
polkitd 999
abrt 173
libstoragemgmt 998
rpc 32
colord 997
saslauth 996
rtkit 172
chrony 995
qemu 107
tss 59
usbmuxd 113
geoclue 994
rpcuser 29
radvd 75
setroubleshoot 993
pulse 171
gdm 42
gnome-initial-setup 992
sshd 74
avahi 70
postfix 89
ntp 38
tcpdump 72
apache 48

[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,NF }' /etc/passwd  
#匹配最后一列为"/bin/bash",输出$1和列数NF的值
root 7
li 7
123 7
12 7
19 7

[root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF }' /etc/passwd
#匹配最后一列为"/bin/bash",输出$1和$NF变量的值
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bash

[root@centos7 ~]# awk -F: '$NF ~ "/bin/bash"{print $1,$NF }' /etc/passwd #
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bash

[root@centos7 ~]# awk -F: '$NF ~ /bash$/{print $1,$NF }' /etc/passwd
root /bin/bash
li /bin/bash
123 /bin/bash
12 /bin/bash
19 /bin/bashm


[root@centos7 ~]# awk -F: '(NR<=28&&NR>=10){print $1}' /etc/passwd
operator
games
ftp
nobody
systemd-network
dbus
polkitd
abrt
libstoragemgmt
rpc
colord
saslauth
rtkit
chrony
qemu
tss
usbmuxd
geoclue
rpcuser


[root@centos7 ~]# awk '/UUID/{print $1}' /etc/fstab
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b

[root@centos7 ~]# awk -F: '/^root\>/,/^ftp\>/{print $1}' /etc/passwd #root开头到ftp开头之间的行 
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator
games
ftp

[root@centos7 ~]# awk -F: 'BEGIN{print "                USER   USERID"}/^root\>/,/^ftp\>/{printf "%20s %s %-5s\n", $1,":",$3}END{print "                 end   file"}' /etc/passwd    
#BEGIN指定(修饰)第一个输出,/^root\>/,/^ftp\>指定(修饰)范围第二个输出,END指定(修饰)最后一个输出范围
                USER   USERID
                root : 0    
                 bin : 1    
              daemon : 2    
                 adm : 3    
                  lp : 4    
                sync : 5    
            shutdown : 6    
                halt : 7    
                mail : 8    
            operator : 11   
               games : 12   
                 ftp : 14   
                 end   file

                 
                 [root@centos7 ~]# awk -F: 'BEGIN{print "user uid \n------------------"}/^root\>/,/^ftp\>/{print $1,$3}' /etc/passwd
user uid
------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14

[root@centos7 ~]# awk -F: 'BEGIN{print "user uid \n------------------"}/^root\>/,/^ftp\>/{print $1,$3}END{print "==============="}' /etc/passwd
user uid
------------------
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
games 12
ftp 14
===============

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 {statments}

while(condition){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){statments}

if(condition){statments} else {statments}

if(condition1){statement1}else if(condition2){statement2} else{statement3} 

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

示例:

[root@centos7 ~]# awk 'BEGIN{ test=100;if(test>90){print "very good"}else if(test>60){ print "good"}else{print "no pass"}}'
very good

成绩为100;大于90打印“very good”;大于60打印“good”;其余打印“no pass”
[root@centos7 ~]# awk '{if($3>=1000){printf "Common user: %s\n",$1 } else{printf "root or sysuser : %s\n",$1}}' /etc/passwd
root or sysuser : root:x:0:0:root:/root:/bin/bash
root or sysuser : bin:x:1:1:bin:/bin:/sbin/nologin
root or sysuser : daemon:x:2:2:daemon:/sbin:/sbin/nologin
root or sysuser : adm:x:3:4:adm:/var/adm:/sbin/nologin
root or sysuser : lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root or sysuser : sync:x:5:0:sync:/sbin:/bin/sync
root or sysuser : shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
root or sysuser : halt:x:7:0:halt:/sbin:/sbin/halt
root or sysuser : mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
root or sysuser : operator:x:11:0:operator:/root:/sbin/nologin
root or sysuser : games:x:12:100:games:/usr/games:/sbin/nologin

[root@centos7 ~]# awk -F: '{if($NF=="/bin/bash")print $1}' /etc/passwd
#NF字段数量,$NF表示最后字段的值,判断字段值等于/bin/bash
root
li
123
12
19

[root@centos7 ~]# awk '{if(NF>5)print $0}' /etc/passwd
#NF字段数量,判断字段数大于5的行
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
[root@centos7 ~]# awk '{if(NF>5)print $0}' /etc/fstab
# Created by anaconda on Tue Jan 9 05:14:54 2018
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff / xfs defaults 0 0
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app xfs defaults 0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot xfs defaults 0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap swap defaults 0 0
[root@centos7 ~]# df -h |awk -F% '{print $1}'
Filesystem Size Used Avail Use
/dev/sda2 20G 3.6G 17G 18
devtmpfs 474M 0 474M 0
tmpfs 489M 0 489M 0
tmpfs 489M 20M 469M 4
tmpfs 489M 0 489M 0
/dev/sda5 20G 33M 20G 1
/dev/sda1 197M 136M 61M 70
tmpfs 98M 36K 98M 1
/dev/sr0 8.1G 8.1G 0 100

[root@centos7 ~]# df -h |awk -F% '{print $1}'|awk '{print $NF}'
Use
18
0
0
4
0
1
70
1
100

[root@centos7 ~]# df -h |awk -F% '/^\/dev/{print $1}'|awk '{print $NF}'
18
1
70
100

#将/etc/passwd第一列当作姓名,第三列当作工资,打印报表,要求显示:
#Name:zhangsan Salary:3300 Level:High
#工资大于3000的,Level显示High,大于1000,小于等于3000的显示Soso,小于1000的显示LOW。 
[root@centos7 ~]#  awk -F: '{if($3>3000){Level="High"}else if($3>1000 && $3<=3000){Level="Soso"}else{Level="Low"};printf "Name:%-20s Salary:%-20d Level:%s\n",$1,$3,Level}' /etc/passwd
Name:root                 Salary:0                    Level:Low
Name:bin                  Salary:1                    Level:Low
Name:daemon               Salary:2                    Level:Low
Name:adm                  Salary:3                    Level:Low
Name:lp                   Salary:4                    Level:Low
Name:sync                 Salary:5                    Level:Low
Name:shutdown             Salary:6                    Level:Low
Name:halt                 Salary:7                    Level:Low
Name:mail                 Salary:8                    Level:Low
Name:operator             Salary:11                   Level:Low
Name:games                Salary:12                   Level:Low
Name:ftp                  Salary:14                   Level:Low
Name:nobody               Salary:99                   Level:Low
Name:systemd-network      Salary:192                  Level:Low
Name:dbus                 Salary:81                   Level:Low
Name:polkitd              Salary:999                  Level:Low
Name:abrt                 Salary:173                  Level:Low
Name:libstoragemgmt       Salary:998                  Level:Low
Name:rpc                  Salary:32                   Level:Low
Name:colord               Salary:997                  Level:Low
Name:saslauth             Salary:996                  Level:Low
Name:rtkit                Salary:172                  Level:Low
Name:chrony               Salary:995                  Level:Low
Name:qemu                 Salary:107                  Level:Low
Name:tss                  Salary:59                   Level:Low
Name:usbmuxd              Salary:113                  Level:Low
Name:geoclue              Salary:994                  Level:Low
Name:rpcuser              Salary:29                   Level:Low
Name:nfsnobody            Salary:65534                Level:High
Name:radvd                Salary:75                   Level:Low
Name:setroubleshoot       Salary:993                  Level:Low
Name:pulse                Salary:171                  Level:Low
Name:gdm                  Salary:42                   Level:Low
Name:gnome-initial-setup  Salary:992                  Level:Low
Name:sshd                 Salary:74                   Level:Low
Name:avahi                Salary:70                   Level:Low
Name:postfix              Salary:89                   Level:Low
Name:ntp                  Salary:38                   Level:Low
Name:tcpdump              Salary:72                   Level:Low
Name:li                   Salary:1000                 Level:Low
Name:apache               Salary:48                   Level:Low
Name:123                  Salary:1001                 Level:Soso
Name:12                   Salary:1002                 Level:Soso
Name:19                   Salary:4444                 Level:High

7.2    while循环

语法:while(condition){statments}

意义:条件”真”,进入循环;条件”假”,退出循环

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

[root@centos7 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){print $1,length($i);i++}}' /etc/grub2.cfg
linux16 7
linux16 30
linux16 46
linux16 2
linux16 4
linux16 5
linux16 16
linux16 7
linux16 50
linux16 46
linux16 2
linux16 4
linux16 5

[root@centos7 ~]# awk '/^[[:space:]]*linux16/{i=1;while(i<=NF){if(length($i)>=40){print $1,length($i)};i++}}' /etc/grub2.cfg
#以空白符开头后跟”linux16″的行中,把字符数大于40的字符串打印出来。
linux16 46
linux16 50
linux16 46

7.3    do-while循环

语法:do {statements} while (condition)

    (无论真假,至少执行一次循环体 )

示例:

[root@centos7 ~]# seq 3|awk 'BEGIN{i=1;print i++,i}'
#i的值:先输出i的值,在做(加法)运算
1 2
[root@centos7 ~]# seq 3|awk 'BEGIN{i=1;print ++i,i}'
#i的值:先做(加法)运算,在输出i 的值
2 2
[root@centos7 ~]# awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
#累加运算:计算0-100之和
5050

7.4    for循环

语法:for(expr1;expr2;expr3) {statement;…} 

常见用法:for(variable assignment;condition;iteration process) {for-body} 

特殊用法:

            能够遍历数组中的元素 

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

示例:

[root@centos7 ~]#  awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print$i,length($i)}}' /etc/grub2.cfg
#遍历:统计以linux16开头的行各字符串出现次数
linux16 7
/vmlinuz-3.10.0-693.el7.x86_64 30
root=UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-ff4aa58d9e1f44f7b7aae5f6fd1a3242 50
root=UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 46
ro 2
rhgb 4
quiet 5

7.5    switch语句

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

7.6    break和continue

break [n] 

continue [n]

awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}’
awk ‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}’

7.7    net

提前结束对本行处理而直接进入下一行处理(awk自身循环) 

示例:

[root@centos7 ~]# awk -F: '{if($3%2!=0)  print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12
ftp 14
systemd-network 192
libstoragemgmt 998
rpc 32
saslauth 996
rtkit 172
geoclue 994
nfsnobody 65534
gdm 42
gnome-initial-setup 992
sshd 74
avahi 70
ntp 38
tcpdump 72
li 1000
apache 48
12 1002
[root@centos7 ~]# seq 20 | awk -F: '{if($1%2==0)next ; print $1}'
#打印奇数行;匹配$1%2取余数的等于0的结束循环
1
3
5
7
9
11
13
15
17
19

8、array(数组 )

关联数组:array[index-expression]

index-expression:

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

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

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

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

for(var in array) {for-body}

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

state["LISTEN"]++

state["ESTABLISHED"]++

9、函数

数值处理:

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

[root@centos7 ~]# awk 'BEGIN{srand();print int(rand()*100)}'
#随机一个两位数的整数,*100
71

字符串处理:

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

sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹 配的内容替换为s

[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'sub(/:/,"-",$1)'
2018-3:30 17:38:30

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

[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'gsub(/:/,"-",$1)'
2018-3-30 17:38:30

split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存 至array所表示的数组中,第一个索引值为1,第二个索引值为2,…

netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++} END{for (i in count) {print i,count[i]}}'
#先进行分割,取出第五列对第五列做分割取出以分隔符:的第一列,设置变量count索引为ip[1]做加法运算,只输出一次结果。

自定义函数

格式:

function name ( parameter, parameter,  ... ) { 
                       statements 
                       return expression 
                                      }

示例:

#cat fun.awk function max(
                v1,v2) { v1>v2?var=v1:var=v2
                 return var
     } 
BEGIN{a=3;b=2;print max(a,b)} 
#awk –f fun.awk

示例:

[root@nana ~]# cat  fi.txt
1 2 3 4 5 6 7 8 9 10
11 12 12 14 15 16 17 18 19 20
[root@nana ~]# awk '{i=1;sum=0;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 显示每行各自的总行
55
155
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 每行显示一次总和
55
210
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++}}END{print sum}' f1.txt 只显示总和
210

对十以内整数奇数输出jishu,偶数输出偶数

效果如下:

1 jishu

2 oushu

3 jishu

[root@centos7 /]# echo {1..10} |awk '{i=1;while(i<=NF){if($i%2==0){print $i,"is oushu"} else{print $i, "is jishu"};i++}}'
1 is jishu
2 is oushu
3 is jishu
4 is oushu
5 is jishu
6 is oushu
7 is jishu
8 is oushu
9 is jishu
10 is oushu
[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
Tuesday
Monday
[root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i] ,i}}'
#i的值为每次数组weekdays的索引,这个过程称为遍历
Tuesday tue
Monday mon

函数统计类型出现次数

~]# netstat -tan |awk '/^tcp\>/{state[$NF]++}END{for (i in state){ print i,state[i]}}'
#函数state中下标为$NF的值:LISTEN和ESTABLISHED,他们的值做++运算,
#END{}:仅在文本完成之后执行一次,后边for循环只做一次,
#i变量的值为:数组state的下标,也就是:LISTEN和ESTABLISHED。
#print i的值为for训话i的值,就是$NF的值:LISTEN和ESTABLISHED。
#state[i]的值为,END前边完成时的值++的相加之和,
#也就是state数组的值:state[LISTEN]=3和state[ESTABLISHED]=1
LISTEN 8
ESTABLISHED 3

显示/bash类型次数

[root@centos7 ~]# awk -F: '{shell[$7]++}END{for(n in shell){print n,shell[n]}}' /etc/passwd
/bin/sync 1
/bin/bash 5
/sbin/nologin 36
/sbin/halt 1
/sbin/shutdown 1

统计http日志文件,IP地址访问次数

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

172.18.253.55 1788
172.18.251.122 52
172.18.251.150 34
172.18.251.141 30
172.18.251.160 157
172.18.251.170 457
172.18.251.107 14
172.18.251.109 51
172.18.251.145 50
172.18.0.223 12
172.18.253.21 74087
::1 15
172.18.251.147 354
172.18.254.78 183
172.18.251.157 330
172.18.252.134 514
172.18.251.149 158
172.18.254.6 1643
172.18.250.183 81
172.18.251.21 81
172.18.254.34 659

awk实现取出从定向

[root@centos7 ~]# awk -F: '! shell[$7]++' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt

去重

[root@centos6 ~]#awk -F: '!shell[$0]++' /etc/passwd #去重

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

#源文件
[root@centos7 ~]# awk '/^UUID/{print $0}' /etc/fstab
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff /                       xfs     defaults        0 0
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e /app                    xfs     defaults        0 0
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c /boot                   xfs     defaults        0 0
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b swap                    swap    defaults        0 0

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

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

[root@centos7 ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab 
UUID=c424d9be-be2c-4e7c-a007-1af750d9310b 1
Tue 1
man 1
and/or 1
UUID=0cd9ec5d-a77e-46f4-b218-19d914a5ed1e 1
maintained 1
xfs 3
Accessible 1
# 7
are 1
defaults 4
Jan 1
blkid(8) 1
/ 1
0 8
See 1
Created 1
05:14:54 1
on 1
mount(8) 1
9 1
anaconda 1
UUID=3535b5f0-7b38-4cc9-a099-551fa388392c 1
fstab(5), 1
/app 1
/boot 1
findfs(8), 1
2018 1
'/dev/disk' 1
by 2
/etc/fstab 1
pages 1
more 1
info 1
swap 2
filesystems, 1
reference, 1
UUID=24d11781-1f0f-4fe5-805c-6ca807fd24ff 1
for 1
under 1

脚本实现AWK

system命令

空格是awk中的字符串连接符,如果system中需要使用awk中 的变量可以使用空格分隔,或者说除了awk的变量外其他一律 用""引用起来。

awk BEGIN'{system("hostname") }' awk 'BEGIN{score=100; system("echo  your score is " score) }'

[root@nanyibo ~]# cat awk.txt
function max(v1,v2){
        v1>v2?var=v1:var=v2
        return var
}
BEGIN{print max(a,b)}
[root@nanyibo ~]# awk -v a=30 -v b=20 -f awk.txt
30
[root@nanyibo ~]# awk -v a=10 -v b=20 -f awk.txt
20

 将awk程序写成脚本,直接调用或执行

示例:

#cat f1.awk 
            {if($3>=1000)print $1,$3} 
#awk -F: -f f1.awk /etc/passwd
#cat f2.awk 
        #!/bin/awk –f 
        #this is a awk script 
        {if($3>=1000)print $1,$3} 
#chmod +x f2.awk 
#f2.awk –F:  /etc/passwd

向awk脚本传递参

格式:

         awkfile  var=value var2=value2... Inputfile

注意:在BEGIN过程中不可用。直到首行输入完成以后,变 量才可用。可以通过-v 参数,让awk在执行BEGIN之前得到 变量的值。命令行中每一个指定的变量都需要一个-v参数

示例:

#cat  test.awk   
        #!/bin/awk –f 
        {if($3 >=min && $3<=max)print $1,$3} 
#chmod +x test.awk 
#test.awk -F: min=100 max=200  /etc/passwd
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值