一、AWK简介:
AWK是一个文本报告生成器,它不仅是Linux中也是任何环境中现有的功能最强大的数据处理引擎之一,它具有编程及数据操作语言,提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、过程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。它允许使用者创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表等等功能。
在最初创造AWK时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。AWK会扫描文件中的每一行,查找与命令行中所给定内容相匹配的内容,如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。
二、AWK语法:
awk [option]...'/PATTERN/{action}' FILE;语法中'/PATTERN/{action}'部分又被称为awk的脚本。
三、AWK基本应用示例:
1、打印文本文件的某个字段,默认分隔符为空格:
[root@client2 html]# awk '{print $1}' /etc/fstab # # # # # # # /dev/mapper/vg0-root UUID=3c74d332-e31d-4368-9e07-74479e1c4ad3 /dev/mapper/vg0-usr /dev/mapper/vg0-var /dev/mapper/vg0-swap tmpfs devpts sysfs proc
2、打印文本文件的多个字段:
[root@client2 html]# awk '{print $1,$2}' /etc/fstab # # /etc/fstab # Created # # Accessible # See # /dev/mapper/vg0-root / UUID=3c74d332-e31d-4368-9e07-74479e1c4ad3 /boot /dev/mapper/vg0-usr /usr /dev/mapper/vg0-var /var /dev/mapper/vg0-swap swap tmpfs /dev/shm devpts /dev/pts sysfs /sys proc /proc
3、打印所有字段,$0用于引用所有字段:
[root@client2 html]# awk '{print $0}' /etc/fstab # # /etc/fstab # Created by anaconda on Mon Jul 28 19:06:01 2014 # # 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 # /dev/mapper/vg0-root / ext4 defaults 1 1 UUID=3c74d332-e31d-4368-9e07-74479e1c4ad3 /boot ext4 defaults 1 2 /dev/mapper/vg0-usr /usr ext4 defaults 1 2 /dev/mapper/vg0-var /var ext4 defaults 1 2 /dev/mapper/vg0-swap swap swap defaults 0 0 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0
4、显示指定的某行的某字段信息或打印连续的若干行:
[root@client1 ~]# awk 'NR==10{print $1}' /etc/fstab UUID=3c74d332-e31d-4368-9e07-74479e1c4ad3 [root@node1 pam.d]# awk 'NR==8,NR==12' /etc/fstab # /dev/mapper/vg0-root / ext4 defaults 1 1 UUID=fbb4629b-1279-4a2a-9f49-18faa0e5bece /boot ext4 defaults 1 2 /dev/mapper/vg0-usr /usr ext4 defaults 1 2 /dev/mapper/vg0-var /var ext4 defaults 1 2
5、NF(Number of Field) 打印每行有几个字段,变量NF用于表示一行内的字段数,在AWK中引用变量时不需要加$,但是如果变量前加了$,如NF,那么就是引用对应的字段的:
[root@client2 html]# awk '{print NF}' /etc/fstab 0 1 2 10 1 9 12 1 6 6 6 6 6 6 6 6 6
6、每行中最后一个字段的调用方式为$NF:
[root@client2 html]# awk '{print $NF}' /etc/fstab # /etc/fstab 2014 # '/dev/disk' info # 1 2 2 2 0 0 0 0 0
7、FS:Field Seperator,输入分隔符,默认是空格:
8、OFS:输出时的字段分隔符
9、语法表达式的/PATTERN/可以使用比较表达式,表达式用>,>=,<,<=,!=,==,~等比较字符来连接,比较的字符串与比较字符不需要用空格隔开,表达式也是正确的:
[root@client2 html]# awk -F: '$3 >= 500{print $1}' /etc/passwd nfsnobody
[root@client2 html]# awk -F: '$3 < 500{print$1}' /etc/passwd root bin daemon adm lp sync shutdown halt mail uucp operator games gopher ftp nobody dbus usbmuxd vcsa rtkit rpc avahi-autoipd abrt haldaemon gdm ntp apache saslauth postfix rpcuser pulse sshd tcpdump
[root@client2 html]# awk -F: '$3 == 0{print $1}' /etc/passwd root
10、模式匹配示例:AWK的模式与action字段之间不需要空格分开,比较表达式两端与比较表达式字符之间不需要空格,而action与要处理的字段之间也不需要空格,整个表达式都连在一起也是正确的,只是属于模式匹配的部分用//括起来,属于action字段的要用{}括起来:
[root@client2 html]# awk -F: '$7~/bash$/{print$1}' /etc/passwd root
11、显示不相邻的多个字段,$1$7连在一起,$1 $7用空格分隔,$1,$7用逗号分隔,注意看显示的效果:
[root@client2 ~]# awk -F: '$7~/bash$/{print$1$7}' /etc/passwd root/bin/bash [root@client2 ~]# awk -F: '$7~/bash$/{print$1 $7}' /etc/passwd root/bin/bash [root@client2 ~]# awk -F: '$7~/bash$/{print$1,$7}' /etc/passwd root /bin/bash
12、AWK中的action字段可以有多个,多个action字段要用{}括起来,比如,在输出的字段前输出表头:
[root@client1 ~]# awk -F: 'BEGIN{print"username shell"}$7~/bash$/{print$1,$7}' /etc/passwd username shell root /bin/bash
下面这条语句是自己测试的语句,写法是错误的,计算机在识别用户输入的命令时所做的语法分析是命令选项参数,参数中又有相对应的格式要求,比如模式和action,而下面语句中的action放在了前面,那么计算机在识别整个字符串的时候就会认为是一个命令加了一个要处理的参数,而我们要表达的模式匹配用来匹配某些行的效果就出不来了,这个字段要写在action的前面,而不能在后面出现,它被计算机识别为了其他的不能识别的字符。而如果要在action中使用多个命令,可以使用;来分隔多个action,模式也是一样,也是用;来分隔开,但是总体上来说,模式和action要有前有后,不能混乱,如果在做模式匹配前,先对行进行一些处理操作,需要使用BEGIN模式,如果要在行处理之后做一些操作就要使用END模式,BEGIN模式是打破了常规的语法顺序的,但是在程序的内部机制上被识别和匹配,而不是语法错误。
[root@client1 ~]# awk -F: '{print"username shell"}$7~/bash$/{print$1,$7}' /etc/passwd
13、显示以bash结尾的且该行的第三字段数值小于500的行的第1和第3字段:
[root@client1 ~]# awk -F: '$7~/bash$/&&$3<500{print$1,$3}' /etc/passwd root 0
14、显示以bash结尾且该行第三个字段数值大于500的行的第1,第3,第7字段:
[root@client1 ~]# awk -F: '$7~/bash$/&&$3>500{print$1,$3,$7}' /etc/passwd
15、显示第三字段数值小于500的行的第1,第3,第7字段,结果中可以看到只有root用户是以bash结尾,所以之前的awk语句的写法是正确的:
[root@client1 ~]# awk -F: '$3<500{print$1,$3,$7}' /etc/passwd root 0 /bin/bash bin 1 /sbin/nologin daemon 2 /sbin/nologin adm 3 /sbin/nologin lp 4 /sbin/nologin sync 5 /bin/sync shutdown 6 /sbin/shutdown halt 7 /sbin/halt mail 8 /sbin/nologin uucp 10 /sbin/nologin operator 11 /sbin/nologin games 12 /sbin/nologin gopher 13 /sbin/nologin ftp 14 /sbin/nologin nobody 99 /sbin/nologin dbus 81 /sbin/nologin usbmuxd 113 /sbin/nologin vcsa 69 /sbin/nologin rtkit 499 /sbin/nologin rpc 32 /sbin/nologin avahi-autoipd 170 /sbin/nologin abrt 173 /sbin/nologin haldaemon 68 /sbin/nologin gdm 42 /sbin/nologin ntp 38 /sbin/nologin apache 48 /sbin/nologin saslauth 498 /sbin/nologin postfix 89 /sbin/nologin rpcuser 29 /sbin/nologin pulse 497 /sbin/nologin sshd 74 /sbin/nologin tcpdump 72 /sbin/nologin
16、BEGIN模式示例,只有BEGIN模式字符开头,后面从能用{}括起来action,后面从有可能再从头查找PATTERN字串:
[root@client1 ~]# awk -F: 'BEGIN{print"username,shell"}$7~/bash$/{print$1,$7}' /etc/passwd username,shell root /bin/bash
要注意多个要显示的字段或者字符串之间如果要用逗号分隔,那么表示他们是不同的字段,如果未指定就要用默认的分隔符分隔开显示,如果这些字段之间没有用逗号分隔,那么默认他们就被连起来显示,在AWK中要表示多个连续的字段,没有类似于其他表达方式的-等等连接符,只能是用其他的方式去遍历需要显示的多个字段。
[root@client1 ~]# awk -F: 'BEGIN{print"username,shell"}$7~/bash$/{print$1,$7}END{print"=====end====="}' /etc/passwd username,shell root /bin/bash =====end=====
17、BEGIN模式:在{action}开始之前执行一次,制作表头;
END模式:在{action}结束之后执行一次,制作表尾;
要从程序的运作机制角度去考虑语句的写法会很容易记忆,写语句时也不容易出错。
而通常情况下BEGIN模式是用来指定输入分隔符和输出分隔符的,用法如下:
[root@client1 ~]# awk 'BEGIN{FS=":"}$7~/bash$/{print$1,$7}' /etc/passwd root /bin/bash [root@client1 ~]# awk 'BEGIN{FS=":";OFS=":"}$7~/bash$/{print$1,$7}' /etc/passwd root:/bin/bash
注意:BEGIN模式和END模式后面的模式字段要用{}括起来,里面的分隔符要用“”引起来表示其为前面变量的值,没有该“”是语法错误,在awk中大写的字符都是有特殊意义的,所以为这个变量赋值的方式就决定了要这样去用,否则就是错误,同样,多个变量之间的赋值操作要用;隔开,否则也是语法错误,都要注意!