一, awk 介绍
awk:Aho, Weinberger, Kernighan, 报告生成器, 格式化文本输出有多种版本: New awk(nawk),GNU awk( gawk)
gawk: 模式扫描和处理语言
基本用法:
- awk [options] 'program' var=value file...
- awk [options] -f programfile var=value file...
- awk [options] 'BEGIN{ action;... } pattern{ action;... } END{ action;... }' file ...
awk 程序通常由: BEGIN 语句块, 能够使用模式匹配的通用语句块, END 语句块, 共 3 部分组成 program 通常是被单引号或双引号中
选项:
-F 指明输入时用到的字段分隔符
-v var=value: 自定义变量?
二, awk 工作原理
第一步: 执行 BEGIN{action;... }语句块中的语句
第二步: 从文件或标准输入 (stdin) 读取一行, 然后执行 pattern{ action;... }语句块, 它逐行扫描文件, 从第一行到最后一行重复这个过程, 直到文件全部被读取完毕.
第三步: 当读至输入流末尾时, 执行 END{action;...}语句块 BEGIN 语句块在 awk 开始从输入流中读取行之前被执行, 这是一个可选的语句块, 比如变量初始化, 打印输出表格的表头等语句通常可以写在 BEGIN 语句块中 END 语句块在 awk 从输入流中读取完所有的行之后即被执行, 比如打印所有行的分析结果这类信息汇总都是在 END 语句块中完成, 它也是一个可选语句块 pattern 语句块中的通用命令是最重要的部分, 也是可选的. 如果没有提供 pattern 语句块, 则默认执行{ print } , 即打印每一个读取到的行, awk 读取的每一行都会执行该语句块.
print 格式: print item1, item2, ...
要点:
(1) 逗号分隔符
(2) 输出的各 item 可以字符串, 也可以是数值; 当前记录的字段, 变量或 awk 的表达式
(3) 如省略 item, 相当于 print $0
示例:
- awk '{print"hello,awk"}'
- awk -F: '{print}' /etc/passwd
三, awk 变量
变量: 内置和自定义变量
FS: 输入字段分隔符, 默认为空白字符
- awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
- awk -F: '{print $1,$3,$7}' /etc/passwd
OFS: 输出字段分隔符, 默认为空白字符
awk -v FS=':' -v OFS=':' '{print $1,$3,$7}' /etc/passwd
RS: 输入记录分隔符, 指定输入时的换行符
awk -v RS='''{print }' /etc/passwd
ORS: 输出记录分隔符, 输出时用指定符号代替换行符
awk -v RS='' -v ORS='###''{print }' /etc/passwd
NF: 字段数量
awk -F: '{print NF}' /etc/fstab, 引用内置变量不用 $
awk -F: '{print $(NF-1)}' /etc/passwd
NR: 记录号
- awk '{print NR}' /etc/fstab
- awk END'{print NR}' /etc/fstab
FNR: 各文件分别计数, 记录号
awk '{print FNR}' /etc/fstab /etc/inittab
FILENAME: 当前文件名
awk '{print FILENAME}' /etc/fstab
ARGC: 命令行参数的个数
- awk '{print ARGC}' /etc/fstab /etc/inittab
- awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
ARGV: 数组, 保存的是命令行所给定的各参数
- awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab
- awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab
自定义变量(区分字符大小写)
(1) -v var=value
(2) 在 program 中直接定义
示例:
- awk -v test='hello gawk' '{print test}' /etc/fstab
- awk -v test='hello gawk' 'BEGIN{print test}'
- awk 'BEGIN{test="hello,gawk";print test}'
- awk -F:'{sex="male";print $1,sex,age;age=18}' /etc/passwd
四, printf 命令
格式化输出: printf "FORMAT", item1, item2, ...
(1) 必须指定 FORMAT
(2) 不会自动换行, 需要显式给出换行控制符,\n
(3) FORMAT 中需要分别为后面每个 item 指定格式符
格式符: 与 item 一一对应
%c: 显示字符的 ASCII 码
%d, %i: 显示十进制整数
%e, %E: 显示科学计数法数值
%f: 显示为浮点数
%g, %G: 以科学计数法或浮点形式显示数值
%s: 显示字符串
%u: 无符号整数
%%: 显示 % 自身
修饰符:
#[.#]: 第一个数字控制显示的宽度; 第二个 #表示小数点后精度,%3.1f
-: 左对齐(默认右对齐) %-15s
+: 显示数值的正负符号 %+d
- awk -F: '{printf"%s",$1}' /etc/passwd
- awk -F: '{printf"%s\n",$1}' /etc/passwd
- awk -F: '{printf"%-20s %10d\n",$1,$3}' /etc/passwd
- awk -F: '{printf"Username: %s\n",$1}' /etc/passwd
- awk -F: '{printf"Username: %s,UID:%d\n",$1,$3}' /etc/passwd
- awk -F: '{printf"Username: %15s,UID:%d\n",$1,$3}' /etc/passwd
- awk -F: '{printf"Username: %-15s,UID:%d\n",$1,$3}' /etc/passwd
五, 操作符
1. 算术操作符:
x+y, x-y, x*y, x/y, x^y, x%y
2. 赋值操作符:
- =, +=, -=, *=, /=, %=, ^=
- ++, --
- awk 'BEGIN{i=0;print ++i,i}'
- awk 'BEGIN{i=0;print i++,i}'
3. 比较操作符:
==, !=,>,>=, <, <=
4. 模式匹配符:
~: 左边是否和右边匹配包含 !~: 是否不匹配
- awk -F: '$0 ~ /root/{print $1}' /etc/passwd
- awk '$0~"^root"' /etc/passwd
- awk '$0 !~ /root/' /etc/passwd
- awk -F: '$3==0' /etc/passwd
5. 逻辑操作符: 与 &&, 或 ||, 非!
- awk -F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
- awk -F: '$3==0 || $3>=1000 {print $1}' /etc/passwd
6. 条件表达式(三目表达式):
- selector?if-true-expression:if-false-expression
- awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf"%15s:%-s\n",$1,usertype}' /etc/passwd
7.PATTERN: 根据 pattern 条件, 过滤匹配的行, 再做处理
(1)如果未指定: 空模式, 匹配每一行
(2) /regular expression/: 仅处理能够模式匹配到的行, 需要用 // 括起来
- awk '/^UUID/{print $1}' /etc/fstab
- awk '!/^UUID/{print $1}' /etc/fstab
(3) relational expression: 关系表达式, 结果为 "真" 才会被处理
真: 结果为非 0 值, 非空字符串
假: 结果为空字符串或 0 值
示例:
- awk -F: 'i=1;j=1{print i,j}' /etc/passwd
- awk '!0' /etc/passwd ; awk '!1' /etc/passwd
- awk -F: '$3>=1000{print $1,$3}' /etc/passwd
- awk -F: '$3<1000{print $1,$3}' /etc/passwd
- awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
- awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
(4) line ranges: 行范围
startline,endline:/pat1/,/pat2/ 不支持直接给出数字格式
- awk -F: '/^root\>/,/^nobody\>/{print $1}' /etc/passwd
- awk -F: '(NR>=10&&NR<=20){print NR,$1}' /etc/passwd
(5) BEGIN/END 模式
BEGIN{}: 仅在开始处理文件中的文本之前执行一次
END{}: 仅在文本处理完成之后执行一次
示例:
- seq 10 |awk 'i=0'
- seq 10 |awk 'i=1'
- seq 10 | awk 'i=!i'
- seq 10 | awk '{i=!i;print i}'
- seq 10 | awk '!(i=!i)'
- seq 10 |awk -v i=1 'i=!i'
六, awk 控制语句
for 循环
语法: for(expr1;expr2;expr3) {statement;...}
常见用法:
- for(variable assignment;condition;iteration process)
- {for-body}
特殊用法: 能够遍历数组中的元素
语法: for(var in array) {for-body}
break 和 continue
- awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}'
- awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}'
- next:
提前结束对本行处理而直接进入下一行处理(awk 自身循环)
awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
也支持 if,while,swich 等编程语句, 这里不多介绍
七, 关联数组: array[index-expression]
index-expression:
? (1) 可使用任意字符串; 字符串要使用双引号括起来
? (2) 如果某数组元素事先不存在, 在引用时, awk 会自动创建此元素, 并将其值
初始化为 "空串"
? 若要判断数组中是否存在某元素, 若要遍历数组中的每个元素, 要使用 for 循环, for(var in array) {for-body}
- awk '!arr[$0]++1' /etc/fstab
- awk '{ip[$1]++}END{for(i in ip) {print i,ip[i]}}' /var/log/httpd/access_log
八, 习题
1, 统计 / etc/fstab 文件中每个文件系统类型出现的次数;
awk '/^[^#]/{fs[$3]++}END{for(i in fs){print i,fs[i]}}' /etc/fstab
2, 统计 / etc/fstab 文件中每个单词出现的次数;
grep -oE "\b[[:alpha:]]+\b" /etc/fstab |awk '{word[$1]++}END{for(i in word){print i,word[i]}}'
3, 提取出字符串 Yd$C@M05MB%9&Bdh7dq+YVixp3vpw 中的所有数字;
- echo 'Yd$C@M05MB%9&Bdh7dq+YVixp3vpw' |awk -F ""'{for(i=1;i<=NF;i++) {if ($i ~ /[:digit:]/){str=$i;str1=(str1 str)}} print str1}'
- echo 'Yd$C@M05MB%9&Bdh7dq+YVixp3vpw'|tr -dc '[:digit:]'
4, 解决 DOS 攻击生产案例: 根据 web 日志或者或者网络连接数, 监控当某个 IP 并发连接数或者短时内 PV 达到 100, 即调用防火墙命令封掉对应的 IP, 监控频率每隔 5 分钟. 防火墙命令为: iptables -A INPUT -s IP -j REJECT
- #!/bin/bash
- file=/var/log/httpd/access_log
- awk '{ip[$1]++}END{for (i in ip){if (ip[i]>100)print i}' $file |while read line ;do
- iptables -A INPUT -s $line -j REJECT
- sleep 300 &
- done
来源: http://www.bubuko.com/infodetail-2604252.html