awk是一个报告生成工具,a program that you can use to select particular records in a file and perform operations upon them.这是官方的解释。linux上使用的是GNU版本的gawk,帮助手册:User Guide
awk是三个作者名字的首字母Aho, Kernighan and Weinberger,功能非常强大,支持正则表达式,支持条件表达式,有内置的变量和函数,支持自定义变量和函数,支持数组,内部支持if ... else,for,case,(do) while,continue,break,next等循环。
awk同sed一样也是一行一行处理,但是他读入一行后会进行切片,默认以空格为分隔符,不管中间有多少个。
常用用法:
awk -F: '/bash$/{print $1,$7}' /etc/passwd
打印默认shell为bash的用户名和shell, -F: 指定:为分隔符,命令要放在花括号里,这样输出格式不是太漂亮,可以用printf(format)带格式的输出以达到输出结果更直观
2. awk -F: '/bash$/{printf "%-15s %s\n",$1,$7}' /etc/passwd
%-15s -代表左对齐,不指定默认是右对齐,15指定输出宽度,s则代表是string字串格式,printf默认不换行,如需换行则要加上换行符\n
%c: 显示字符的ASCII码;
%d, %i:十进制整数;
%e, %E:科学计数法显示数值;
%f: 显示浮点数;
%g, %G: 以科学计数法的格式或浮点数的格式显示数值;
%s: 显示字符串;
%u: 无符号整数;
%%: 显示%自身;
3. awk -F: '$3>500{printf "%10s %d\n",$1,$3}' /etc/passwd
打印出uid>500的用户
4. awk -F: 'BEGIN{print "User Shell";OFS=" --> "}$3>500 && $7~/bash$/ {print $1,$7}END{print "========END========="}' /etc/passwd
BEGIN模式可以做一些预处理动作,OFS(Output File Seprator)指定输出的分隔符,OFS对printf无效且要放在BEGIN模块的print语句后面,否则不生效
FS: field separator,读取文件本时,所使用字段分隔符;
RS: Record separator,输入文本信息所使用的换行符;
ORS:Output Row Separator:
END模式则是处理结束后做些收尾工作
条件之间可以做逻辑运算 && ||等
5. netstat -tan | awk '/^tcp/{print $6}' | uniq -c | sort -rn
统计tcp各连接状态的连接数并按降序排列
6. netstat -ant | awk '/^tcp/{++STATE[$NF]};END {for (KEY in STATE) printf "%-15s %i\n", KEY,STATE[KEY]}'
分别统计每种连接状态的连接数,STATE为数组名,以$NF即最后一个filed也就是连接状态为下标,每遇到一个相同的状态数组对应的的元素值则+1从而达到统计的目的,统计结束打印出数组下标和对应的值。
7. 内置变量NR和FNR用于用awk命令分析多个文件场景,FNR记录的是当前读入的行在当前的文件的行数,NR则记录的是当前总共读入多少行。
FNR The input record number in the current input file.
NR The total number of input records seen so far.
// NR和FNR的区别 [root@bob ~]# cat name 张三 10亿 李四 200万 王五 100千 [root@bob ~]# cat info 上海 张三 北京 李四 南京 王五 [root@bob ~]# awk '{print NR,FNR}' name info 1 1 2 2 3 3 4 1 5 2 6 3
8. 合并显示两个文件:
awk 'FNR==NR{arr[$1]=$0;next}{print arr[$2],$1}' name info
next是awk内置命令,提前结束本行处理,$0代表整行内容,FNR=NR时则读取的是第一个文件,第一个文件处理结束,用next命令结束对数组arr的赋值动作,再处理第二个文件时,就直接执行打印命令,这里我故意把info这个文件中的姓名放在后面,所以后面print中数组引用的下标也要相应的换成$2.
当然也可以不用next命令,后面再加个FNR<NR条件效果也是一样的,这条命令也可以写成
awk 'FNR==NR{arr[$1]=$0}FNR<NR{print arr[$2],$1}' name info
[root@bob ~]# awk 'FNR==NR{arr[$1]=$0;next}{print arr[$2],$1}' name info 张三 10亿 上海 李四 200万 北京 王五 100千 南京
9. 自定义变量:-v
嵌套if语句统计UID>100的用户个数
awk -F: -v sum=0 '{if ($3>=100) {sum++;}};END{print sum}' /etc/passwd
if语句也可以不用
awk -F: -v sum=0 '$3>100{sum++}END{print sum}' /etc/passwd