awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

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


语法:

awk [options] 'program' file file ...

awk [options] 'PATTERN{action}' file file ...

-F CHAR:指定分隔符

awk的输出:

print item1, item2,...


要点:

(1) 各项目之间使用逗号分隔,而输出时则使用输出分隔符分隔

[root@localhost ~]# awk -F ":" '/^root/ {print $1,$7}' /etc/passwd

root /bin/bash


(2) 输出的各item可以是字符串或数值、当前记录的字段、变量或awk的表达式;数值会被隐式转换为字符串后输出

[root@localhost ~]# cat /etc/passwd |awk -F ':' 'BEGIN {print "name shell"} {print $1,$7}'

name shell

root /bin/bash

bin /sbin/nologin

daemon /sbin/nologin

adm /sbin/nologin

lp /sbin/nologin


(3) print后面item如果省略,相当于print $0;输出空白,使用pirnt ""

[root@localhost ~]# awk -F ":" '/^root/ {print}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

[root@localhost ~]# awk -F ":" '/^root/ {print $0}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

[root@localhost ~]# awk -F ":" '/^root/ {print ""}' /etc/passwd


awk的变量:

内置变量,自定义变量

(1) 内置变量:

FS:Field Seperator, 输入时的字段分隔符(相当于-F:)

RS:Record Seperator, 输入行分隔符

OFS: Output Field Seperator, 输出时的字段分隔符

ORS: Outpput Row Seperator, 输出时的行分隔符

NF:Numbers of Field,字段数

NR:Numbers of Record, 行数;所有文件的一并计数

FNR:行数;各文件分别计数

ARGV:数组,保存命令本身这个字符,awk '{print $0}' 1.txt 2.txt,意味着ARGV[0]保存awk,

ARGC: 保存awk命令中参数的个数

FILENAME: awk正在处理的当前文件的名称

示例:

使用FS指定分隔符

[root@localhost ~]# awk 'BEGIN{FS=":"} {print $1,$7}' /etc/passwd

root /bin/bash

bin /sbin/nologin

daemon /sbin/nologin

adm /sbin/nologin

lp /sbin/nologin

sync /bin/sync


统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容

[root@localhost ~]# awk -F ":" '{print "filename:"FILENAME",linenumber:"NR",columns:"NF",linecontent:" $0 }' /etc/passwd

filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash

filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin


自定义变量

-v var_name=VALUE

变量名区分字符大小写

(1) 可以program中定义变量

(2) 可以命令行中通过-v选项自定义变量


示例:统计/etc/passwd的账户人数

[root@localhost ~]# awk -F: '{count++;print $0} END{print "user count is", count}' /etc/passwd

root:x:0:0:root:/root:/bin/bash

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

user count is 5


printf命令

命令的使用格式:printf format, item1, item2,...

要点:

(1) 要指定format;

(2) 不会自动换行;如需换行则需要给出\n

(3) format用于为后面的每个item指定其输出格式;


format格式的指示符都%开头,后跟一个字符:

%c: 显示字符的ASCII码;

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

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

%f: 显示浮点数;

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

%s: 显示字符串;

%u: 显示无符号整数;

%%: 显示%自身;


修饰符:

#:显示宽度

-:左对齐

+:显示数值的符号

.#: 取值精度


示例:显示用户的UID

[root@localhost ~]# awk -F: '{printf "UID: %d\n",$3}' /etc/passwd

UID: 0

UID: 1

UID: 2

UID: 3

UID: 4

UID: 5

UID: 6

UID: 7

UID: 8


统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容

[root@localhost ~]# awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd

filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash

filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin


awk的操作符

算术操作符:

x+y

x-y

x*y

x/y

x**y, x^y

x%y

-x:负值

+x:转换为数值


字符串操作符:连接


赋值操作符:

=

+=

-=

*=

/=

%=

^=

**=

++

--

如果模式自身是=号,要写为/=/


比较操作符:

<

<=

>

>=

==

!=

~:模式匹配,左边的字符串能够被右边的模式所匹配为真,否则为假;

!~:

逻辑操作符:

&&: 与

||:或


条件表达式:

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

示例:查看用户的UID大于500显示为普通用户,否则显示为管理员或系统用户

[root@localhost ~]# awk -F: '{$3>500?utype="Common User":utype="Admin or Syetem user";print $1, "is", utype}' /etc/passwd

root is Admin or Syetem user

bin is Admin or Syetem user

daemon is Admin or Syetem user

adm is Admin or Syetem user

user9 is Common User

user10 is Common User


模式:

(1) Regexp: 格式为/PATTERN/

仅处理被/PATTERN/匹配到的行

(2) Expression: 表达式,其结果为非0或非空字符串时满足条件

仅处理满足条件的行

(3) Ranges: 行范围,此前地址定界

NR 仅处理范围内的行

(4) BEGIN/END: 特殊模式,仅在awk命令的program运行之前(BEGIN)或运行之后(END)执行一次

(5) Empty:空模式,匹配任意行


示例:显示用户名以及Shell类型

[root@localhost ~]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd

root /bin/bash

mk /bin/bash

bash /bin/bash

testbash /bin/bash

basher /bin/bash


显示指定范围内的用户名以及Shell类型

[root@localhost ~]# awk -F: 'NR>=1&&NR<=5{print $1,$NF}' /etc/passwd

root /bin/bash

bin /sbin/nologin

daemon /sbin/nologin

adm /sbin/nologin

lp /sbin/nologin


统计某个文件夹下的文件占用的字节数

[root@localhost ~]# ll /etc/ |awk 'BEGIN {size=0} {size=size+$5} END{print "[end]size is ",size}'

[end]size is 1995496


统计某个文件夹下的文件占用的字节数,以M为单位显示

[root@localhost ~]# ll /etc/ |awk 'BEGIN {size=0} {size=size+$5} END{print "[end]size is ",size/1024/1024,"M"}'

[end]size is 1.90305 M


常用的action:

(1) Expressions

(2) Control statements

(3) Compound statements

(4) input statements

(5) output statements


控制语句:

if-else

格式:if (condition) {then body} else {else body}

判断用户UID大小并显示用户的类型

[root@localhost ~]# awk -F: '{if ($3>=500) {print $1 "is a Common User"} else {print $1 "is a Admin or System User"}}' /etc/passwd

rootis a Admin or System User

binis a Admin or System User

user9is a Common User

user10is a Common User


判断用户UID与GID是否相同

[root@localhost ~]# awk -F: '{if ($3=$4) {print $1 "is a good guy"} else {print $1 "is a bad guy"}}' /etc/passwd

rootis a bad guy

binis a good guy

daemonis a good guy

admis a good guy

lpis a good guy

syncis a bad guy


while

格式:while (condition) {while body}

显示文件的奇数行

[root@localhost ~]# awk '{i=1;while (i<=NF){printf "%s",$i;i+=2};print""}' /etc/inittab

#isusedupstarttherunlevel.

#

#OTHERHEREHAVEEFFECTYOUR

#

#initializationstarted/etc/init/rcS.conf


do-while循环

格式:do {do-while body} while (condition)

for循环

格式:for (variable assignment; condition; iteration process) {for body}


示例:查看访问web服务器的每个IP的访问次数

[root@localhost ~]# ab -n 10000 -c 100 http://192.168.111.128/index.html(网站访问压力测试)

This is ApacheBench, Version 2.3 <$Revision: 655654 $>

Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/

Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.111.128 (be patient)

Completed 1000 requests

Completed 2000 requests

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

192.168.111.128 30031


next

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


示例:打印奇数用户

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

bin 1

adm 3

sync 5

[root@localhost ~]# awk -F: '{if(NR%2==0) next;print NR,$1}' /etc/passwd

1 root

3 daemon

5 lp


数组

传统数组:Index编号从1开始;

关联数组:

array[index-expression]

index-expression: 可以使用任意字符串; 如果某数组元素事先不存在,那么在引用时,awk会自动创建此元素并将其初始化为空串;因此,要判断某数组是否存在某元素,必须使用“index in array”这种格式;

A[first]="hello awk"

print A[second]

要遍历数组中的每一个元素,需要使用如下特殊结构:

for (var in array) {for body}

其var会遍历array的索引;

state[LISTEN]++

state[ESTABLISHED]++


示例:显示LISTEN 或ESTABLISHED等链接状态的次数

[root@localhost ~]# netstat -tan | awk '/^tcp/{++state[$NF]}END{for (s in state) {print s,state[s]}}'

ESTABLISHED 1

LISTEN 11


示例:查看访问web服务器的每个IP的访问次数

[root@localhost ~]# ab -n 10000 -c 100 http://192.168.111.128/index.html(网站压力测试)

This is ApacheBench, Version 2.3 <$Revision: 655654 $>

Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/

Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.111.128 (be patient)

Completed 1000 requests

Completed 2000 requests

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

192.168.111.128 30031


删除数组元素:

delete array[index]


awk的内置函数

split(string,array[,fieldsep[,seps]]):

功能:将string表示的字符串以fieldsep为分隔符进行切片,并切片后的结果保存至array为名的数组中;数组下标从1开始;

root:x:0:0::/root:/bin/bash

user[1]="root", user[2]

此函数有返回值,返回值为切片后的元素的个数

[root@localhost ~]# netstat -tn | awk '/^tcp/{lens=split($5,client,":");ip[client[1]]++}END{for (i in ip) print i,ip[i]}'

192.168.111.1 1


length(string)

功能:返回给定字串的长度

substr(string,start[,length])

功能:从string中取子串,从start为起始位置为取length长度的子串;