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) 各项目之间使用逗号分隔,而输出时则使用输出分隔符分隔
[[email protected] ~]# awk -F ":" ‘/^root/ {print $1,$7}‘ /etc/passwd
root /bin/bash
(2) 输出的各item可以是字符串或数值、当前记录的字段、变量或awk的表达式;数值会被隐式转换为字符串后输出
[[email protected] ~]# 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 ""
[[email protected] ~]# awk -F ":" ‘/^root/ {print}‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
[[email protected] ~]# awk -F ":" ‘/^root/ {print $0}‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
[[email protected] ~]# 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指定分隔符
[[email protected] ~]# 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:文件名,每行的行号,每行的列数,对应的完整行内容
[[email protected] ~]# 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的账户人数
[[email protected] ~]# 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
[[email protected] ~]# 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:文件名,每行的行号,每行的列数,对应的完整行内容
[[email protected] ~]# 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显示为普通用户,否则显示为管理员或系统用户
[[email protected] ~]# 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类型
[[email protected] ~]# 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类型
[[email protected] ~]# 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
统计某个文件夹下的文件占用的字节数
[[email protected] ~]# ll /etc/ |awk ‘BEGIN {size=0} {size=size+$5} END{print "[end]size is ",size}‘
[end]size is 1995496
统计某个文件夹下的文件占用的字节数,以M为单位显示
[[email protected] ~]# 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大小并显示用户的类型
[[email protected] ~]# 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是否相同
[[email protected] ~]# 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}
显示文件的奇数行
[[email protected] ~]# 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的访问次数
[[email protected] ~]# 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
[[email protected] ~]# awk ‘{ip[$1]++}END{for (i in ip) {print i,ip[i]} }‘ /var/log/httpd/access_log
192.168.111.128 30031
next
提前结束对本行的处理进而提前进入下一行的处理;
示例:打印奇数用户
[[email protected] ~]# awk -F: ‘{if($3%2==0) next;print $1,$3}‘ /etc/passwd
bin 1
adm 3
sync 5
[[email protected] ~]# 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等链接状态的次数
[[email protected] ~]# netstat -tan | awk ‘/^tcp/{++state[$NF]}END{for (s in state) {print s,state[s]}}‘
ESTABLISHED 1
LISTEN 11
示例:查看访问web服务器的每个IP的访问次数
[[email protected] ~]# 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
[[email protected] ~]# 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]
此函数有返回值,返回值为切片后的元素的个数
[[email protected] ~]# 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长度的子串;