一、AWK
1.简介
AWK是一个优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人阿尔佛雷德·艾侯、彼得·温伯格和布莱恩·柯林汉姓氏的首个字母)的最大功能取决于一个人所拥有的知识,很多事情往往都是这样。
我们可以在linux环境中使用它来进行快速的、任意规模的数据统计分析。大到几十G、小到随手统计文件信息均可。
2.使用
示例数据:log.txt
1,aa a,ccc,aw qr
2,ss ss,d dd,e e e,ll l
3,0 0,98 u,kj lh,ll x,2 23,hh
4,23 3,s ss
1)取出指定列(默认分隔符为 空格:“ ”):awk '{print $1,$4}' log.txt
$x表示第x列。
root@ubuntu:/leonRain/test# awk '{print $1,$4}' log.txt
1 awqr
2 eee
3 kjlh
4
2)取出指定列并格式化输出:awk '{printf "%-3s %-18s %-3s\n",$1,$4,$1}' log.txt
{printf "%-3s %-18s %-3s\n",$1,$4,$1}:第1列与第4列隔3个空格,第4列与再一个第1列隔18个空格,最后加3个空格
root@ubuntu:/leonRain/test# awk '{printf "%-3s %-18s %-3s\n",$1,$4,$1}' log.txt
1 awqr 1
2 eee 2
3 kjlh 3
4 4
x)使用新示例数据log2.txt:
root@ubuntu:/leonRain/test# cat log2.txt
1,aa a,ccc,aw qr
2,ss ss,d dd,e e e,ll l
3,0 0,98 u,kj lh,ll x,2 23,hh
4,23 3,s ss
3)指定分隔符:awk -F, '{print $1,$2}' log2.txt
“-F,”:以","为分隔符
使用内建变量:awk 'BEGIN{FS=","} {print $1,$2}' log.txt
root@ubuntu:/leonRain/test# awk -F, '{print $1,$2}' log2.txt
1 aa a
2 ss ss
3 0 0
4 23 3
root@ubuntu:/leonRain/test# awk 'BEGIN{FS=","} {print $1,$2}' log2.txt
1 aa a
2 ss ss
3 0 0
4 23 3
4)使用多个分隔符,先使用空格分割,然后对分割结果再使用","分割。最后的分割结果在同一层。
$ awk -F '[ ,]' '{print $1,$2,$5}' log2.txt
root@ubuntu:/leonRain/test# awk -F '[ ,]' '{print $1,$2,$5}' log2.txt
1 aa aw
2 ss dd
3 0 u
4 23 ss
5)设置 数值型 变量:(例如:设置a=1,b=8)
awk -va=1 -vb=8 '{print $1,$1+a,$1*b}' log2.txt
root@ubuntu:/leonRain/test# awk -va=1 -vb=8 '{print $1,$1+a,$1*b}' log2.txt
1,aa 2 8
2,ss 3 16
3,0 4 24
4,23 5 32
6)设置 字符(串)型 变量(例如:设置a=1,b=s)
awk -va=1 -vb=s '{print $1,$1+a,$1b}' log2.txt
root@ubuntu:/leonRain/test# awk -va=1 -vb=s '{print $1,$1+a,$1b}' log2.txt
1,aa 2 1,aas
2,ss 3 2,sss
3,0 4 3,0s
4,23 5 4,23s
7)执行awk脚本:awk -f {awk脚本} {文件名}
实例: $ awk -f cal.awk log.txt
(编写awk脚本稍后介绍。)
8)逻辑运算:单引号中可以使用使用 条件表达式 实现过滤。
awk '$1>2' log2.txt
root@ubuntu:/leonRain/test# awk '$1>2' log2.txt
2,ss ss,d dd,e e e,ll l
3,0 0,98 u,kj lh,ll x,2 23,hh
4,23 3,s ss
9)单引号中还可以加入{print …}来指定要打印出符合条件的数据的哪些列。
awk '$1>3 {print $1,$2,$3}' log2.txt
root@ubuntu:/leonRain/test# awk '$1>3 {print $1,$2,$3}' log2.txt
3,0 0,98 u,kj
4,23 3,s ss
10)多条件查询,找到第一列大于3,且第三列等于“ss”的。
awk '$1>3 && $3=="ss" {print $1,$2,$3}' log2.txt
root@ubuntu:/leonRain/test# awk '$1>3 && $3=="ss" {print $1,$2,$3}' log2.txt
4,23 3,s ss
11)输出内置函数结果值
示例数据3:
root@ubuntu:/leonRain/test# cat log3.txt
11,222,333,444,555
12,222,332,111,444
13,123,1243,999,4
14,25,12,333,1
15,99,99,99,99
16,22,22,22,44
17,11,11,11,11
查看这些数据的所在文件名,命令行参数的数目。。。等内容(可查表得知这些代码对应的内置函数功能,表格在附录2)
awk -F, 'BEGIN{printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR","OFS","ORS","RS";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS}' log3.txt
root@ubuntu:/leonRain/test# awk -F, 'BEGIN{printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR","OFS","ORS","RS";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS}' log3.txt
FILENAME ARGC FNR FS NF NR OFS ORS RS
---------------------------------------------
log3.txt 2 1 , 5 1
log3.txt 2 2 , 5 2
log3.txt 2 3 , 5 3
log3.txt 2 4 , 5 4
log3.txt 2 5 , 5 5
log3.txt 2 6 , 5 6
log3.txt 2 7 , 5 7
黄色部分打印表头,绿色部分是真正的定制结果,即格式化输出:“FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS”这些内容。
12)亦可直接在 单引号中使用
awk '{print NR,FNR,$1,$2,$3}' log3.txt
root@ubuntu:/leonRain/test# awk '{print NR,FNR,$1,$2,$3}' log.txt
1 1 1 aaa ccc
2 2 2 ssss ddd
3 3 3 00 98u
4 4 4 233 ssSSs
13)指定输出时的字段分隔符
awk '{print $1,$2,$5}' OFS=" $ " log3.txt
root@ubuntu:/leonRain/test# awk -F, '{print $1,$2,$5}' OFS=" $ " log3.txt
11 $ 222 $ 555
12 $ 222 $ 444
13 $ 123 $ 4
14 $ 25 $ 1
15 $ 99 $ 99
16 $ 22 $ 44
17 $ 11 $ 11
14)通过正则表达式匹配,查找第二列中包含"ab"的数据,并输出其第二和第四列。
awk '$2 ~ /a/ {print $2,$4}' log.txt
root@ubuntu:/leonRain/test# awk '$2 ~ /a/ {print $2,$4}' log.txt
aaa awqr
若指定在某列中匹配,语法为:'$列号 ~ /匹配条件/' 例如:awk '$2 ~ /s/' log2.txt
若在整条数据中匹配,则不需要使用"~",语法为:awk '/s/' log2.txt
awk '$2 ~ /s/ && $3 ~ /s/' log2.txt
root@ubuntu:/leonRain/test# awk '$2 ~ /s/ && $3 ~ /s/' log2.txt
4,23 3,s ss
xx)使用新的示例数据:
root@ubuntu:/leonRain/test# cat logstr.txt
this is a dog;
This is a dog;
Are you ok?
are you OK?
15)模式取反,即利用感叹号“!”进行条件取反
awk '$1 !~ /this/' logstr.txt
root@ubuntu:/leonRain/test# awk '$1 !~ /this/' logstr.txt
This is a dog;
Are you ok?
are you OK?
16)awk脚本编写
关于 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"
}
# 运行中 规定遍历数据时的具体操作。这里进行的是变量与具体列的逐行累加,
# 同时输出该行数据及一些计算值,如这里最后输出了一个总分 $3+$4+$5。
{
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
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
17)拓展
统计文件大小:
ls -l *.txt | awk '{sum+=$5} END {print sum}'
这段命令分为两部分:“ls -l *.txt ”作用是查看当前所在路径下的.txt后缀的文件信息。
“awk '{sum+=$5} END {print sum}'”作用是对出入数据的第五列进行统计,并在结束时输出结果。
root@ubuntu:/leonRain/test# ll
total 28
drwxr-xr-x 2 root root 4096 May 27 16:20 ./
drwxr-xr-x 20 root root 4096 May 27 13:55 ../
-rw-r--r-- 1 root root 84 May 27 14:41 log2.txt
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt
-rw-r--r-- 1 root root 54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root 72 May 27 16:09 log.txt
-rwxr-xr-x 1 root root 38 May 27 14:56 tt.awk*
root@ubuntu:/leonRain/test# ls -l *.txt | awk '{sum+=$5} END {print sum}'
326
找到当前目录中属于root用户的文件:
ls -l * | awk '$4 ~ /root/'
root@ubuntu:/leonRain/test# ll
total 28
drwxr-xr-x 2 root root 4096 May 27 16:20 ./
drwxr-xr-x 20 root root 4096 May 27 13:55 ../
-rw-r--r-- 1 root root 84 May 27 14:41 log2.txt
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt
-rw-r--r-- 1 root root 54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root 72 May 27 16:09 log.txt
-rwxr-xr-x 1 root root 38 May 27 14:56 tt.awk*
root@ubuntu:/leonRain/test# ls -l * | awk '$4 ~ /root/'
-rw-r--r-- 1 root root 84 May 27 14:41 log2.txt
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt
-rw-r--r-- 1 root root 54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root 72 May 27 16:09 log.txt
-rwxr-xr-x 1 root root 38 May 27 14:56 tt.awk
我们可以利用上面这种方法,将常用的linux命令与awk结合使用,即:将常用linux命令的输出结果作为awk的输入数据,对结果进行过滤、统计等常规简易操作。
附录1.awk逻辑运算说明表
运算符 | 描述 |
= += -= *= /= %=(取模赋值) ^=(异或赋值) **=(幂赋值) | 赋值 |
?: | C条件表达式 |
|| | 逻辑或 |
&& | 逻辑与 |
~ 和 !~ | 匹配正则表达式和不匹配正则表达式 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / % | 乘,除与求余 |
+ - ! | 一元加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 增加或减少,作为前缀或后缀 |
$ | 字段引用 |
in | 数组成员 |
附录2.awk内建变量表
变量 | 描述 |
$n | 当前记录的第n个字段,字段间由FS分隔 |
$0 | 完整的输入记录 |
ARGC | 命令行参数的数目 |
ARGIND | 命令行中当前文件的位置(从0开始算) |
ARGV | 包含命令行参数的数组 |
CONVFMT | 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组 |
ERRNO | 最后一个系统错误的描述 |
FIELDWIDTHS | 字段宽度列表(用空格键分隔) |
FILENAME | 当前文件名 |
FNR | 各文件分别计数的行号 |
FS | 字段分隔符(默认是任何空格) |
IGNORECASE | 如果为真,则进行忽略大小写的匹配 |
NF | 一条记录的字段的数目 |
NR | 已经读出的记录数,就是行号,从1开始 |
OFMT | 数字的输出格式(默认值是%.6g) |
OFS | 输出记录分隔符(输出换行符),输出时用指定的符号代替换行符 |
ORS | 输出记录分隔符(默认值是一个换行符) |
RLENGTH | 由match函数所匹配的字符串的长度 |
RS | 记录分隔符(默认是一个换行符) |
RSTART | 由match函数所匹配的字符串的第一个位置 |
SUBSEP | 数组下标分隔符(默认值是/034) |
二、sort
1.简介
排序操作也是经常使用的,它可以通过sort命令实现。
2.示例
语法:sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符>][+<起始栏位>-<结束栏位>][--help][--verison][文件]
sort [-b 或 c 或 d…r均可][-o<输出文件>][-t<分隔字符>][+<起始栏位>-<结束栏位>][--help][--verison][文件]
1)对当前目录所有文件按大小排序。(第五列表示文件大小,因此用-k5,默认是正序排列,若需倒序可使用-rk5)
ll * | sort -n -k5
-rwxr-xr-x 1 root root 38 May 27 14:56 tt.awk*
-rw-r--r-- 1 root root 54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root 72 May 27 16:09 log.txt
-rw-r--r-- 1 root root 84 May 27 14:41 log2.txt
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt
2)对当前目录所有文件按修改时间排序。
ll * | sort -n -k8
-rw-r--r-- 1 root root 84 May 27 14:41 log2.txt
-rwxr-xr-x 1 root root 38 May 27 14:56 tt.awk*
-rw-r--r-- 1 root root 116 May 27 15:43 log3.txt
-rw-r--r-- 1 root root 54 May 27 16:20 logstr.txt
-rw-r--r-- 1 root root 72 May 27 16:09 log.txt
3)sort还可以用来处理文件。
查看原始数据文件:
root@ubuntu:/leonRain/test# cat log.txt
1 aaa ccc awqr
2 ssss ddd eee lll
3 00 98u kjlh llx 223 hh
4 233 ssSSs
使用sort对其进行默认排序:
root@ubuntu:/leonRain/test# sort log.txt
1 aaa ccc awqr
2 ssss ddd eee lll
3 00 98u kjlh llx 223 hh
4 233 ssSSs
使用sort对其进行倒序排序:
root@ubuntu:/leonRain/test# sort -r log.txt
4 233 ssSSs
3 00 98u kjlh llx 223 hh
2 ssss ddd eee lll
1 aaa ccc awqr
使用sort按其第二列进行倒序排序:
root@ubuntu:/leonRain/test# sort -rk2 log.txt
2 ssss ddd eee lll
1 aaa ccc awqr
4 233 ssSSs
3 00 98u kjlh llx 223 hh
参数说明:
-b 忽略每行前面开始出的空格字符。
-c 检查文件是否已经按照顺序排序。
-d 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
-f 排序时,将小写字母视为大写字母。
-i 排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
-m 将几个排序好的文件进行合并。
-M 将前面3个字母依照月份的缩写进行排序。
-n 依照数值的大小排序。
-u 意味着是唯一的(unique),输出的结果是去完重了的。
-o<输出文件> 将排序后的结果存入指定的文件。
-r 以相反的顺序来排序。
-t<分隔字符> 指定排序时所用的栏位分隔字符。
+<起始栏位>-<结束栏位> 以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。
--help 显示帮助。
--version 显示版本信息。