awk: 报告生成器
格式化后显示信息
语法:
- awk [options] 'script' file1 file2, ...
- awk [options] 'PARTTERN { action }' file1 file2, ...
最常见的 action:print,printf
awk 的基本特征:
a. 每一次取一行
b. 根据指定的分隔符 (不指定是位空白字符) 将该行切割位列, 使用 $0(整行),$1,$2,$3...(第一列, 第二列,...)
c. 可以指定行号, 列号, 切割符, 操作后分隔符
案例:
chkconfig --list |grep 3: 启用 |awk '{print $1}'
- tail -1 /etc/passwd |awk -F ':' 'BEGIN{OFS="---"}{print $1,$6,$7}' ##OFS 指定输出分隔符
- ifconfig eth1 |awk -F '[ :]+' 'NR==2 {print $4}'
- ifconfig eth1 |awk -F '[ :]+' 'NR==2 {print"eth1_ip="$4}' ## 可以加入显示内容
- awk 'BEGIN {print"line one \nline two\nline three"}'
4. 高级 awk 的使用:
1)awk 变量:
FS: 列分隔符, 默认位空白
RS: 行分隔符, 默认位换行符
OFS: 输出列分隔符
ORS : 输出行分隔符
2)awk 内置变量
NR: 处理中行数
FNR: 单个文件的行数
NF: 列的个数
案例:
- ifconfig eth1 |awk '{print NR}'
- ifconfig eth1 |awk '{print NF}'
3) 自定义变量:
- awk 'BEGIN{test="www.linuxfan.cn";print test}'
- awk -v test="linuxfan.cn" 'BEGIN{print test}'
- 4)printf
使用的格式:
printf format, item1,item2, ...
特征:
a. 必须指定 format, 用于指定后面 item 的输出格式
b.printf 语句不会自动打印换行符:\n
c.format 格式以 %+ 一个字符, 如下:
%c: 显示字符的 ASCII 码
%d,%i: 十进制整数
%e: 科学计数法显示数值
%f: 显示浮点数 (小数)
%s: 显示字符串
%u: 无符号整数
%%: 显示 %
d. 修饰符: N: 显示宽度,-: 左对齐,+: 显示数值符号, 如 %-c(左对齐)
案例:
chkconfig --list |grep 3: 启用 |awk '{printf"%-10s",$1}' ## 在统一行显示
awk -F : '{printf"%-15s %-10d %-10s\n",$1,$3,$7}' /etc/passwd
5)awk 的操作符
a. 算数操作符
- -x
- +x
- x^y
- x*y
- xy
- x/y
- x+y
- x-y
- x%y
b. 赋值操作符
- +=
- -=
- *=
- /=
- %=
- ++
c. 布尔值
awk 中, 任何非 0 值或者非空字符串都为真, 反之为假
d. 比较操作符:>,<,>=,<=,==,!=,~,!~(x ~ y, 字符串能被表达式 y 匹配)
d. 逻辑操作符:&&,||,!
e. 条件表达式: 条件? if-true-exp:if-false-exp
f. 调用函数: function_name (pa1, pa2)
6)awk 常见的模式类型:
a. 正则表达式 (regexp), 格式为:/regular expression/
awk -F : '/^u/{print $1}' /etc/passwd
b. 表达式 (expression), 值位非 0 或位非空是满足条件, 如 $1 ~ /foo / 或 $1 == "root"
- awk -F : '$3>=500{print $1,$3,$7}' /etc/passwd
- awk -F : '$3+1<=100&&$3+1>=10{print $1,$3,$7}' /etc/passwd
- awk -F : '$2=="!!"{print $1,$2}' /etc/shadow ## 检查未初始化密码的用户
- passwd -d u01
- awk -F : '$2==""{print $1}' /etc/shadow ## 打印密码为空的用户
- awk -F : '$7~"bash$"{print $1,$3,$7}' /etc/passwd ## 匹配 $7 为 bash 结束行
- awk -F : '$7!~"bash$"{print $1,$3,$7}' /etc/passwd
c. 匹配范围 (ranges), 指定的匹配范围, 格式为 part1,part2
- awk -F : '$3==3,$3==10{print $1,$3,$7}' /etc/passwd
- awk -F : '$1=="root",$1=="adm"{print $1,$3,$7}' /etc/passwd
- awk -F : '/^r/,/^a/{print $1,$3,$7}' /etc/passwd
d. 特殊模式 (BEGIN/END)
- awk -F : 'BEGIN{printf"%-10s%-10s%-20s\n","UserName","ID","Shell"}{printf"%-10s%-10s%-20s\n",$1,$3,$7}' /etc/passwd ## 在 awk 处理之前打印头部 BEGIN{
- }
- awk -F : 'BEGIN{printf"%-10s%-10s%-20s\n","UserName","ID","Shell"}$7~"bash$"{printf"%-10s%-10s%-20s\n",$1,$3,$7}' /etc/passwd ## 多个模式混合使用
- awk -F : 'BEGIN{printf"%-10s%-10s%-20s\n","UserName","ID","Shell"}$7~"bash$"{printf"%-10s%-10s%-20s\n",$1,$3,$7}END{print"End of report"}' /etc/passwd ## 在 awk 执行完成后打印尾部 END{
- }
- awk -v i=1 '$5~"yum"{i++}END{print"yum use times:", i}' /var/log/messages
/ 正则表达式 /: 使用通配符的扩展集合.
关系表达式: 如字符串或数字的比较.
模式匹配表达式: 模式 (指定一个行的范围, 不包含 BEGIN,END)
7) 常见的 action:
expressions: 表达式
control satatements: 控制语句
compound statements: 混合语句
input statements: 输入语句
output statements: 输出语句
8)action 中的控制语句:
a.if-else
语法: if (condition) command action1; else command action2
案例:
- awk -F : '$7~"bash"{if ($1=="root") print $1,"admin";else print $1,"Common User"}' /etc/passwd
- awk -F : -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd
- awk -F : -v sum=0 '$7~"bash"{if ($1=="root") print $1,"admin"sum++;else print $1,"Common User"sum++}END{print"can login user num:",sum}' /etc/passwd ## 二合一
- awk -F : '$7~"bash$"{if ($1=="root") printf"%-15s: %s\n",$1,"admin";else printf"%-15s: %s\n",$1,"common user"}' /etc/passwd ## 格式化输出
b.while 循环: 循环字段, awk 本身就是行的循环
语法: while (condition){statement1;statement2;...}
案例:
- awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd ## 循环打印前 3 列
- awk -F : '{
- i=1;while (i /etc/passwd ## 循环整行, 并打印出长度小于 4 的字段列
- c.do-while
语法: do {statement1;statement2;...} while (condition)
- awk -F : '{i=1;do {print $i;i++}while(i<=3)}' /etc/passwd
- d.for
语法: for (variable assignment;condition;iteration process){statement1, statement2,...}
案例:
awk -F : '{for(i=1;i<=3;i++) print $i}' /etc/passwd
for 循环遍历数组元素:
语法: for (i in array) {statement1, statement2,...}
案例:
- awk -F : '{SH[$NF]++;}END{for (i in SH){print i,SH[i]}}' /etc/passwd
- netstat -ant |awk '/^tcp/{++S[$NF]}END{for(a in S) print a, S[a]}'
- awk '{counts[$1]++}END{for (url in counts) print url,"access times:",counts[url]}' /var/log/httpd/access_log
- awk '{S[$5]++}END{for (i in S) print i,S[i]}' /var/log/messages
- awk '{AH[$1]++}END{for (i in AH) printf"%-20s:%s\n", i, AH[i]}' /var/log/httpd/access_log
9).awk 中的数组
array[index-expression]
index-expression 可以使用任意字符串; 需要注意的是, 如果某数据组元素事先不存在, 那么在引用其时, awk 会自动创建此元素并初始化为空串; 因此, 要判断某数据组中是否存在某元素, 需要使用 index in array 的方式. 要遍历数组中的每一个元素, 需要使用如下的特殊结构:
for (var in array) { statement1, ... }
例如:
- state[abc]=3
- state[efg]=6
- for (A in state) {
- print A,state[A]
- } ##A 一定是 index-expression(下标 abc/efg),state[A] 是一个具体的值 (3/6)
- [[email protected] ~]# netstat -ant
- Active Internet connections (servers and established)
- Proto Recv-Q Send-Q Local Address Foreign Address State
- tcp 0 0 0.0.0.0:22 0.0.0.0:LISTEN
- tcp 0 0 127.0.0.1:25 0.0.0.0: LISTEN
- tcp 0 0 192.168.1.106:22 192.168.1.101:36318 ESTABLISHED
以上命令显示的结果中, 每一行最后一个字段为状态, 若要统计每种状态的个数, 只需要将 state 作为数组下标, 由于 awk 本身就是一个行的循环, 所以只需要给数字自加 1(++) 即可实现统计, 具体操作如下:
netstat -ant |awk '{S[$6]++}END{for(i in S){print i,S[i]}}'
10)awk 的内置函数
split(string,array[filedsep[,seps]])
作用: 将 string 表示的字符串以 fieldsep 为分隔符进行分隔, 并将分隔后的结果保存至 array 为名的数组中; 数组下标为从 0 开始的序列;
- netstat -ant | awk '/:80\>/{split($5,clients,":");IP[clients[1]]++}END{for(i in IP){print IP[i],i}}' | sort -rn | head -50
- length([string])
功能: 返回 string 字符串中字符的个数;
substr(string, start [, length])
功能: 取 string 字符串中的子串, 从 start 开始, 取 length 个; start 从 1 开始计数;
system(command)
功能: 执行系统 command 并将结果返回至 awk 命令
systime()
功能: 取系统当前时间
tolower(s)
功能: 将 s 中的所有字母转为小写
toupper(s)
功能: 将 s 中的所有字母转为大写
来源: http://www.bubuko.com/infodetail-3090813.html