grep,sed和awk称作文本处理三剑客,下面介绍一下awk的基本用法
awk:man手册上的意思为:pattern scanning and processing language;
意为样式扫描和处理语言
awk是一个数据处理工具,常用于一整行的处理,将读入的行进行分段,
每一行的每个字段有变量名称的,$1,$2..$NF.
awk的强大之处还在于它是一个格式化的报告生成工具;支持文本处理过滤,脚本编程,
在一个语句内部还可实现循环。
一:语法格式:
awk [option] 'script' file1,file2,...
awk [option] 'PATTERN {action}'
awk ‘条件类型1{动作1}条件类型2{动作2}...’ filename
awk 'BEGIN{print "start"}PATTERN{ commands }END{print "end"}' filename
BEGIN语句块 + 能够使用模式匹配的通用语句块 + END语句块
常用的表示:
默认分隔符是空格
-F:指定字段分隔符
$0表示引用整行
$1表示第一行
$2表示第二行
NF:每一行拥有的字段总数
NR:目前awk所处理的是第几行数据
FS:目前的分隔符,默认是空格
$NF:每一行的最后一个字段
-v OFS= 表示输出的段分隔符是什么
二:printf:格式化的显示命令
printf format,itam1,itam2,...
要点:
1、与print命令的最大不同是,printf需要指定格式
2、format用于指定后面的每个item的输出格式
3、printf不会自动打印换行符
format格式的指示符都以%开头,后跟一个字符,如:
%c:显示字符的ASCII码
%d,%i:十进制
%e:%E:科学计算法显示数值
%f:显示浮点数
%s:显示字符串
%u:无符号整数
%%:显示%自身
修饰符:
N:显示宽度
-:左对齐
+:显示数值符号
默认是右对齐的
例1:
[root@localhost ~]# awk '{printf "%10s,%s\n", $1,$2}' a.txt
welcome,to
how,to
[root@localhost ~]# awk '{printf "%-10s%s\n", $1,$2}' a.txt
welcome to
how to
三:awk的操作符
1、算术操作符
-x:负值
+x:转换为数值
x^y,x**y:次方
x*y:乘法
x/y
x+y
x-y
x%y
2:赋值操作符
= += -= /= %= ^= **= ++ --
3:比较操作符
x < y
X <= y
X > Y
x >= y
x == Y
x != y
x ~ y 取模能够被匹配;y是模式
x !~ y 取模不能够被匹配
例2:awk -F: '$1 ~ /^root/ {print $3,$4,$NF}' /etc/passwd
$1 ~ /^root/ 用来做模式匹配的,如果能够匹配第一字段开头是root的,
则显示它的$3,$4,$NF
四:作匹配的情况:
1、正则表达式:格式为/regular expression/
[root@localhost ~]# awk -F : '/bash/{print $1,$NF}' /etc/passwd
root /bin/bash
student /bin/bash
visitor /bin/bash
2、表达式:其值为非0或为非空时满足条件;如 %1 ~ /foo
或$1 == "hadoop" 使用运算符~(匹配)和!~(不匹配)
[root@localhost ~]# awk -F: '$3>=500{print $3,$NF}' /etc/passwd
65534 /sbin/nologin
500 /bin/bash
501 /bin/bash
3、指定的匹配范围的
格式:pat1,pat2
/bash/,/awk/ 第一次被/bash/匹配的开始,到第一次被/awk匹配的结束
4、BEGIN/END 特殊模式,仅在awk命令执行前运行一次或结束前运行一次
# awk -F: 'BEGIN{print "USER UID"}{printf "%-12s%s\n",$1,$3}END{print "Over"}' /etc/passwd
USER UID ##加上用户和UID号
root 0
bin 1
daemon 2
adm 3
...
Over ##提醒结束的信息
//使用BEGIN和ENG分别在输出的内容的开头和结尾加上我们希望的信息;
五:在awk中可以使用各种控制语句:
- eg:
- # awk -F: '{if ($1==“root”) print $1,"Admin"; else print $1,"common
- User"}' /etc/passwd
- root admin
- bin common user
- daemon common user
- ...
- //如果第一个字段是“root”的话就显示它是Admin,否则显示时"common
- User";这样用一条命令就实现了对用户的用户的分类
- 同样,/etc/passwd中第三个字段是用户的ID号,我们知道只有root的ID号为零
- ,那么以此也可用来区分root和普通用户:
- # awk -F: '{if ($3==0) print $1,"Admin";else print $1, "common
- user"}' /etc/passwd
- 也可将结果以左对齐较整齐的输出:
- # awk -F: '{if ($3==0) printf "%-15s: %s\n",$1,"Admin";else printf
- "%-15s: %s\n", $1, "common user"}' /etc/passwd
- 用if-else求和:
- # awk -F: -v sum=0 '{if ($3<=500) sum++}END{print sum}' /etc/passwd
2、while语句
语法:while (condition)(statement1;statement2;...)
- # awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd
- # awk -F: '$1~/root/{i=1;while (i<=NF) {print $i ;i+=2}}' /etc/passwd
- root
- 0
- root
- /bin/bash
- //先选取匹配root的行,然后显示奇数片段的结果
- 所以在awk中,可以实现将(如/etc/passwd中的)每一行切片处理(以:为分隔符),然后对每一片段的结果做处理
3、do-while
语法:do (statement1; statement2;...) while (contion)
先执行一次循环再做判断,这和while语句不同
满足条件就执行循环,不满足就退出
# awk -F: '{i=1;do {print $i;i++} while(i<=3)}' /etc/passwd
4、for语句
用于循环次数已知的循序;
语法:for (初始值;判断条件;变量条件) {stattement1;statement2,...}
- # awk -F: '{for(i=1;i<=3;i++){print $i}}' /etc/passwd
- //while,do-while和for循序有时能都可用于循环,类似于C语言风格;其中fo
- r最常用
- for循环还可以用来遍历属组元素:
- 语法:for (i in array) {statement1;statement2;...}
- # awk -F: '$NF!~/^$/{BASH[$NF]++}END{for(A in BASH){printf
- "%15s:%i\n",A,BASH[A]}}' /etc/passwd
- /bin/sync:1
- /bin/bash:3
- /sbin/nologin:28
- /sbin/halt:1
- /sbin/shutdown:1
- 求1-100之和:
- # seq 1 100 | awk '{a+=$1}END{print a}'
- 5050
5、case
语法:switch (expression) {case VALUE or /REDEXP/: statement1;statement2;...}
6、break,continue
常用于循环和case语句中
7、next.
提前结束对文本的处理,并接着处理下一行
六、awk中数组的使用:
array[index-expression]
index-expression可以使用任意字符串,但如果某数组元素事先不存在,那么在引用时,awk会自动创建次元素并初始化为空串;
因此,要判断某数组中是否存在某元素,需要使用Index in array的方式
要遍历属组中的每一个元素,使用如下方式:
语法:for (var in array) {statement1;statement2;...}
//var用于引用数组下标
例3:用awk显示netstat中每一种状态的和:
- 例:用awk显示netstat中每一种状态的和:
- [root@localhost ~]# netstat -ant
- Active Internet connections (servers and established)
- Proto Recv-Q Send-Q Local Address Foreign Address State
- tcp 0 0 127.0.0.1:2208 0.0.0.0:* LISTEN
- tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
- tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN
- tcp 0 0 0.0.0.0:946 0.0.0.0:* LISTEN
- tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
- tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
- tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
- tcp 0 0 127.0.0.1:6011 0.0.0.0:* LISTEN
- tcp 0 0 127.0.0.1:2207 0.0.0.0:* LISTEN
- tcp 0 132 172.16.14.14:22 172.16.0.1:49750 ESTABLISHED
- # netstat -ant|awk '$1~/tcp/{S[$NF]++}END{for(i in S) print i,S[i]}'
- LISTEN 9
- ESTABLISHED 1
- ##$NF是最后一段的值;即LISTEN或ESTABLISHED
- ##把最后一个片段当做数组的下标
- ##任何一个变量没声明之前它的初始值为零,$[$NF]开始时为0,
- ## S[$NF]++变量整个循环后,所有LISTEN的个数保存在S[LISTEN]中,
- ## 所有ESTABLISHED的个数保存在S[ESTABLISHED]中;
- ##i是数组的下标;代表的值有ESTABLISHED和LISTEN
- ##上面命令中的S[i],当i为LISTEN时,表示S[LISTEN]的个数
- ##当i为ESTABLISHED;表示S[ESTABLISHED]的个数
- 对输出结果规范化:
- # netstat -ant|awk '$1~/tcp/{S[$NF]++}END{for(i in S) printf "%12s:%s\n", i,S[i]}'
- LISTEN:9
- ESTABLISHED:1
- 例4:统计/etc/passwd最后一个非空片段的个数
- # awk -F: '$NF!~/^$/{S[$NF]++}END{for(i in S)printf "%-15s: %s\n", i,S[i]}' /etc/passwd
- /bin/sync : 1
- /bin/bash : 3
- /sbin/nologin : 28
- /sbin/halt : 1
- /sbin/shutdown : 1
- 例5:统计访问日志中访问本服务器的ip次数:
- # cd /usr/local/apache/logs
- # awk '{IP[$1]++}END{for(i in IP) print i,IP[i]}' access_log
- 192.168.0.243 137
- ##由此可见,awk是个报告生成工具
七、awk的内置函数
split(string,array [,fieldsep [seps] ])
功能:将string表示的字符串以fieldsep为分隔符进行分割,
并将分割后的结果保存至array为名字的数组中
- 如:
- netstat -ant|awk
- '/:80/{split($5,clients,":");IP[clients[1]]++}END{for(i in
- IP){print i,IP[i]}}' |sort -rn | head -50
- ##过滤“:80”的行,对第五个字段以":"进行切割,将结果保存至clients中,
- ##IP[clients[1]]是一个数组,数组的下标是切割后的客户端IP,
- 最后显示每一个IP的访问次数
- ##将一个数组的内容当做另一个数组的下标
- ##当一个IP的访问次数过多时,有故意攻击之嫌,这时可采取措施应对