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一样也是一行一行处理,但是他读入一行后会进行切片,默认以空格为分隔符,不管中间有多少个。


常用用法:

  1. 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    


    1. %-15s -代表左对齐,不指定默认是右对齐,15指定输出宽度,s则代表是string字串格式,printf默认不换行,如需换行则要加上换行符\n

    2. %c: 显示字符的ASCII码;

    3. %d, %i:十进制整数;

    4. %e, %E:科学计数法显示数值;

    5. %f: 显示浮点数;

    6. %g, %G: 以科学计数法的格式或浮点数的格式显示数值;

    7. %s: 显示字符串;

    8. %u: 无符号整数;

    9. %%: 显示%自身;


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


    1. BEGIN模式可以做一些预处理动作,OFS(Output File Seprator)指定输出的分隔符,OFS对printf无效且要放在BEGIN模块的print语句后面,否则不生效

    2. FS: field separator,读取文件本时,所使用字段分隔符;

    3. RS: Record separator,输入文本信息所使用的换行符;

    4. ORS:Output Row Separator:

    5. END模式则是处理结束后做些收尾工作

    6. 条件之间可以做逻辑运算 && ||等

      wKiom1QhHtTDG9zLAABefdSpHnc701.jpg


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

awk 'FNR==NR{arr[$1]=$0}FNR$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