基础

数据

cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62

cat netstat.txt
Proto Recv-Q Send-Q Local-Address          Foreign-Address             State
tcp        0      0 0.0.0.0:3306           0.0.0.0:*                   LISTEN
tcp        0      0 0.0.0.0:80             0.0.0.0:*                   LISTEN
tcp        0      0 127.0.0.1:9000         0.0.0.0:*                   LISTEN
tcp        0      0 coolshell.cn:80        124.205.5.146:18245         TIME_WAIT
tcp        0      0 coolshell.cn:80        61.140.101.185:37538        FIN_WAIT2
tcp        0      0 coolshell.cn:80        110.194.134.189:1032        ESTABLISHED
tcp        0      0 coolshell.cn:80        123.169.124.111:49809       ESTABLISHED
tcp        0      0 coolshell.cn:80        116.234.127.77:11502        FIN_WAIT2
tcp        0      0 coolshell.cn:80        123.169.124.111:49829       ESTABLISHED
tcp        0      0 coolshell.cn:80        183.60.215.36:36970         TIME_WAIT
tcp        0   4166 coolshell.cn:80        61.148.242.38:30901         ESTABLISHED
tcp        0      1 coolshell.cn:80        124.152.181.209:26825       FIN_WAIT1
tcp        0      0 coolshell.cn:80        110.194.134.189:4796        ESTABLISHED
tcp        0      0 coolshell.cn:80        183.60.212.163:51082        TIME_WAIT
tcp        0      1 coolshell.cn:80        208.115.113.92:50601        LAST_ACK
tcp        0      0 coolshell.cn:80        123.169.124.111:49840       ESTABLISHED
tcp        0      0 coolshell.cn:80        117.136.20.85:50025         FIN_WAIT2
tcp        0      0 :::22                  :::*                        LISTEN

字段

awk '{print $0}' demo.txt
# $0代表当前行,$1、$2、$3分别代表第1、2、3个字段

分隔符

1)默认分隔符为空格或制表符

2)指定分隔符为冒号
awk -F: '{print $1}' /etc/passwd
awk -F':' '{print $1}' /etc/passwd

3)多个字符作为分隔符
awk 'BEGIN{FS="\",\""}{print NF}' a.txt

4)多个分隔符
awk -F '[:; ]+' '{print $1}' a.txt
# +表示多个连在一起的分隔符算一个

参考资料:
关于其中的一些知识点可以参看gawk的手册:http://www.gnu.org/software/gawk/manual/gawk.html
内建变量,参看:http://www.gnu.org/software/gawk/manual/gawk.html#Built_002din-Variables
流控方面,参看:http://www.gnu.org/software/gawk/manual/gawk.html#Statements
内建函数,参看:http://www.gnu.org/software/gawk/manual/gawk.html#Built_002din
正则表达式,参看:http://www.gnu.org/software/gawk/manual/gawk.html#Regexp

变量

# 输出行号
head -4 netstat.txt | awk '{print NR, $3, $6}'
$0:当前记录(这个变量中存放着整个行的内容)
$1~$n:当前记录的第n个字段,字段间由FS分隔
FS:字段分隔符,默认是空格和制表符。
NF:当前记录中的字段个数,就是有多少列
NR:已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中。
FNR:当前记录数,与NR不同的是,这个值会是各个文件自己的行号
RS:行分隔符,用于分割每一行,默认是换行符。
OFS:输出字段的分隔符,用于打印时分隔字段,默认为空格。
ORS:输出记录的分隔符,用于打印时分隔记录,默认为换行符。
OFMT:数字输出的格式,默认为%.6g。
FILENAME:当前文件名

函数

awk -F ':' '{ print toupper($1) }' demo.txt
toupper()用于将字符转为大写
tolower():字符转为小写。
length():返回字符串长度。
substr():返回子字符串。
sin():正弦。
cos():余弦。
sqrt():平方根。
rand():随机数。

过滤,条件

# 格式
awk '条件 动作' 文件名
# 输出包含usr的行
awk -F ':' '/usr/ {print $1}' demo.txt
# 输出奇数行
awk -F ':' 'NR % 2 == 1 {print $1}' demo.txt
# 输出第三行以后的行
awk -F ':' 'NR >3 {print $1}' demo.txt
# 输出第一个字段等于指定值的行
awk -F ':' '$1 == "root" {print $1}' demo.txt
awk -F ':' '$1 == "root" || $1 == "bin" {print $1}' demo.txt
# 第三个字段大于0
awk ' $3>0 {print $0}' netstat.txt
# 第三个字段等于0并且第6个字段为LISTEN并且输出表头
awk '$3==0 && $6=="LISTEN" || NR==1 ' demo.txt
# 第6个字段匹配模式,~表示模式开始,//中是模式(其实就是一个正则表达式的匹配)
awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' demo.txt
# 模式取反
awk '$6 !~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' demo.txt

过滤,if语句

# 输出第一个字段的第一个字符大于m的行
awk -F ':' '{if ($1 > "m") print $1}' demo.txt
awk -F ':' '{if ($1 > "m") print $1; else print "---"}' demo.txt

拆分文件

awk 'NR!=1{print > $6}' netstat.txt
awk 'NR!=1{print $0 > $6}' netstat.txt

统计

# 计算所有的C文件,CPP文件和H文件的文件大小总和
ls -l  *.cpp *.c *.h | awk '{sum+=$5} END {print sum}'
# 统计各个connection状态的用法
awk 'NR!=1{a[$6]++;} END {for (i in a) print i ", " a[i];}' netstat.txt
# 统计每个用户的进程的占了多少内存
ps aux | awk 'NR!=1{a[$1]+=$6;} END { for(i in a) print i ", " a[i]"KB";}'

脚本

$ cat cal.awk
#!/bin/awk -f
#运行前
BEGIN {
    math = 0
    english = 0
    computer = 0
 
    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
#运行中
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
    printf "---------------------------------------------\n"
    printf "  TOTAL:%10d %8d %8d \n", math, english, computer
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}

# 执行脚本
awk -f cal.awk score.txt