shark AWK 练习
原文链接 https://www.jianshu.com/p/3f771928670c
AWK
$ cat gy.txt
机构号 机构名称 省别 尾箱号 尾箱状态 领用柜员号 领用柜员姓名 币种 余额
11007eee 北京东城区街支行 北京 03 未领用 156 19001.68
11007fff 北京东城区街支行 北京 03 未领用 840 2672.00
11007aaa 北京东城区街支行 北京 04 未领用 156 7261.31
11007ccc 北京朝阳区路支行 北京 02 未领用 156 161490.08
110088ee 北京朝阳区路支行 北京 03 未领用 840 19711.00
34009eff 山西煤矿区路支行 山西 03 未领用 156 282370.23
11007eee 山西煤矿区路支行 山西 03 未领用 156 282370.23
11007eee 山西煤矿区路支行 山西 03 未领用 156 282370.23
11007264 山东平阴县支行 山东 02 未领用 156 304516.23
11007889 山东济阳县支行 北京 04 未领用 840 24551.00
11007264 北京朝阳区支行 北京 02 未领用 156 304516.23
11007284 北京朝阳区支行 北京 02 领用 1002 巫妖王 156 304516.23
11007194 北京朝阳区行 北京 02 未领用 156 304516.23
11007264 河南中原区支行 河南 02 未领用 156 304516.23
过滤记录
过滤条件为:
awk '$3=="河南" && $5 == "未领用" {print $6,$7}' qf.txt
其中的 ==
为比较运算符。其他比较运算符:!=, >, <, >=, <=
各种过滤记录的方式:
$ awk ' $4 > 3 {print $0}' gy.txt
如果我们需要表头的话,我们可以引入内置变量NR:
$ awk '$3=="山东" && $5=="未领用" || NR==1 ' gy.txt
再加上格式化输出:
$ awk '$3=="山东" && $5=="未领用" || NR==1 {printf "%-10s %-21s %-6s\n",$1,$2,$3}' gy.txt
字符串匹配
示例:
查找 平阴县支行的所有信息
awk '$2 ~ /平阴县/ || NR==1 {print NR, $1,$4}' gy.txt
~
表示模式开始。
/ /
中是模式。这就是一个正则表达式的匹配。
其实awk可以像grep一样,进行逐行匹配,就像这样:
$ awk '/.*县/' gy.txt
我们可以使用 “/平阴县|济阳县/” 来匹配 平阴县 或者 济阳县 :
$ awk '$2 ~ /平阴县|济阳县/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" gy.txt
再来看看模式取反的例子:
$ awk '$2 !~ /平阴县/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" gy.txt
或是:
$ awk '!/平阴县/' gy.txt
折分文件
awk拆分文件很简单,使用重定向就好了。
下面这个例子,是按第 3 例分隔文件,相当的简单(其中的NR!=1表示不处理表头)。
$ awk 'NR!=1{print > $3}' gy.txt
$ ls
gy.txt 北京 山东 山西 山东 河南
你也可以把指定的列输出到文件:
awk 'NR!=1{print $2,$4,$5 > $3}' gy.txt
再复杂一点:(注意其中的if-else-if语句,可见awk其实是个脚本解释器)
$ awk 'NR!=1 {if($3 ~ /北京|山东/) print > "1.txt";
else if($3 ~ /山西/) print > "2.txt";
else print > "3.txt" }' gy.txt
$ ls ?.txt
1.txt 2.txt 3.txt
统计
下面的命令计算所有的 txt 文件的文件大小总和。
$ ls -l *.txt | awk '{sum+=$5} END {print sum}'
2511401
我们再来看一个统计各个各省份网点数量的用法:
$ awk 'NR!=1 {a[$3]++;} END {for (i in a) print i ", " a[i];}' gy.txt
北京, 69
山西, 20
江苏, 10
山东, 16
a
是数组名称
[$3]
是数组的索引号,这个索引号可以是普通字符
i
是for
循环 数组 得到的 索引号
a[i]
是获取到索引对应的值
再来看看统计每个用户的进程的占了多少内存(注:sum的RSS那一列)
$ ps aux | awk 'NR!=1 {a[$1]+=$6;} END { for(i in a) print i ", " a[i]"KB";}'
awk脚本
BEGIN
和 END
,这两个关键字意味着执行前和执行后的意思,语法如下:
BEGIN { 这里面放的是执行前的语句 }
END {这里面放的是处理完所有的行后要执行的语句 }
{这里面放的是处理每一行时要执行的语句}
示例:
假设有这么一个文件(学生成绩表):
$ 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
我们的awk脚本如下:
$ 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
}
我们来看一下执行结果:(也可以这样运行 ./cal.awk score.txt)
$ awk -f cal.awk score.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry 2143 78 84 77 239
Jack 2321 66 78 45 189
Tom 2122 48 77 71 196
Mike 2537 87 97 95 279
Bob 2415 40 57 62 159
---------------------------------------------
TOTAL: 319 393 350
AVERAGE: 63.80 78.60 70.00
环境变量
怎么和环境变量交互:(使用-v参数和ENVIRON,使用ENVIRON的环境变量需要export)
$ x=5
$ y=10
$ export y
$ echo $x $y
5 10
$ awk -v val=$x '{print $1, $2, $3, $4+val, $5+ENVIRON["y"]}' OFS="\t" score.txt
Marry 2143 78 89 87
Jack 2321 66 83 55
Tom 2122 48 82 81
Mike 2537 87 102 105
Bob 2415 40 62 72
最后,我们再来看几个小例子:
#从file文件中找出长度大于80的行
awk 'length>80' file
#按连接数查看客户端IP
netstat -ntu | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -nr
#打印99乘法表
seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'
关于其中的一些知识点可以参看gawk的手册:
内建变量,参看: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
"""
# 访问TOP 20 的IP
16348 58.16.183.52
awk '$9==200 {print $1}' 2018-05-10-0000-2330_app.log | sort |uniq -c |sort -r |head -20
访问状态码为20X的 TOP 10的IP
2097 125.70.184.99
2000 183.225.69.158
awk '$9 > 200 && $9 < 300{print $1}' 2018-05-10-0000-2330_app.log | sort |uniq -c |sort -r |head
访问TOP 20 的url
250563 http://app.xxx.com/update/2018-04-04/dangbeimarket_4.0.9_162_znds.apk
awk '$9 == 200{print $7,$9}' 2018-05-10-0000-2330_app.log | sort |uniq -c |sort -r |head -20
访问状态码为20X的 TOP 10的url
248786 http://app.znds.com/update/2018-04-04/dangbeimarket_4.0.9_162_znds.apk
awk '$9 > 200 && $9 < 300{print $7,$9}' 2018-05-10-0000-2330_app.log | sort |uniq -c |sort -r |head
访问次数超过1W的IP
58.16.184.247
58.16.183.52
awk '{print $1}' 2018-05-10-0000-2330_app.log| sort |uniq -c |sort -r |awk '$1 > 10000 {print $1}'
访问状态码为404的 TOP 10的url
1017 http://app.xxx.com/update/fixedaddress/kuaisou_qcast.apk.md5
awk '$9 == 404 {print $1}' 2018-05-10-0000-2330_app.log | sort |uniq -c |sort -r |head
"""