awk
awk是一种用于处理文本的编程语言工具,他扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式,如果发现匹配内容,则进行下一个编程步骤。如果找 不到匹配内容,则继续处理下一行
awk ‘条件 1 {动作 1} 条件 2 {动作 2} ……’ file
从 file 中每次读取一行,然后针对这一行判断条件 1,成立则执行动作 1, 否则不执行,然后判断条件 2,成立则执行动作 2,否则不执行,以此类推。如果一个动作 前面没有条件,则这个动作就可以“无条件”执行
内建变量
- $0 当前记录(这个变量中存放着整个行的内容)
- $1~$n 当前记录的第 n 个字段,字段间由
- FS 分隔 FS 输入字段分隔符 默认是空格或 Tab
- NF 当前记录中的字段个数,就是有多少列
- NR 行号,从1开始,如果有多个文件这个值将不断累加。
- FNR 当前记录数,与 NR 不同的是,这个值会是各个文件自己的行号
- RS 输入的记录分隔符, 默认为换行符
- OFS 输出字段分隔符, 默认也是空格
- ORS 输出的记录分隔符,默认为换行符
- FILENAME 当前输入文件的名字
例子1 读取文件
awk ‘NR==1 { print $0 } NF==5 { print $1 }’ file
awk 从 file 中读取数据,每次读取一行,读到一行数据之后 判断每一个条件是否成立,如果成立则执行花括号里面的动作,比如 NR==1 成立则执行 print $0,然后再判断 NF==5 是否成立来决定是否执行 print $1。然后读取下一行,以 此类推
例子2 输出txt
有下面一个txt文件
- 打印指定列(例如名字和年龄)
awk ‘{ print $1, $5 }’ grade.txt
从 grade.txt 中读取一行,然后执行条件语句(该 示例中没有条件语句),然后执行动作(即 print $1, $5)。完了继续读取下一行,就这 样循环递进
- 格式化输出(和 C 语言一样)
awk ‘{printf "%-10s:%-d\n", $1, $5}’ grade.txt
- 过滤
awk ‘$5==11 && $6>=90 { print $0 }’ grade.txt
:读取 grade.txt 的一行信息,判断第五列(即$5)是否等于 11 而且第 6 列(即$6) 是否大于等于 90,如果是,则打印整一行(即 print $0)。然后读取下一行。
- 打印表头,引入内建变量 NR
awk ‘NR==1 || $6>=90 { print }’ grade.txt
注意:1,NR 是一个所谓的内建变量,表示已经读出的记录数(即行号) 2,print 后面什么都没跟,等价于 print $0
例子3 指定分隔符
awk ‘BEGIN { FS=”:” } { print $1 }' /etc/passwd
等价于
awk -F: ‘{ print $1 }’ /etc/passwd
BEGIN 意味着紧跟在它后面的动作{FS=”:”}会在 awk
- 如果有多个分隔符
awk -F‘[\t;:]’ ‘{ print $1 }’ /etc/passwd
其中-F’[\t;:]’的意思是:指定制表符、分号以及冒号为分隔符。
例子4 使用正则表达式匹配字符串
awk ‘$0~/Brown/ {print}’ grade.txt
将所有匹配 Brown 的行打印出来。其中,$0~/Brown/是一个条件,表示所指定 的域(这里是$0)要匹配的规则(这里是 Brown),也就是说,grade.txt 中的一行只要 包含有单词 Brown,就会被选出来然后打印出来。
这里的单词 Brown 被包含在两个正斜杠之间,事实上这两个正斜杠之间写 的就是大名鼎鼎的“正则表达式”,就是RE
grep ‘[^ ]*ing ’ example.txt 查询txt中ing结尾的字符在哪一行并输出
特殊符号
例子5 使用模式取反的例子
awk '$0!~/Brown.*/ {print}' grade.txt
将所有不匹配 Brown 的行打印出来
例子6 拆分文件
将各年龄段的孩子的信息分别存放在各个文件中
awk '{print > $5}' grade.txt
每一行都将被重定向到以第 5 个域(年龄)命名的文件中去
也可以将指定的域重定位到相应的文件
awk '{print $1, $6 > $5}' grade.txt
将每一行中的姓名和分数重定位到与其年龄相应的文件中去
例子7 按级别将信息分成三个文件
awk '{ if($4~/Brown.*|Black/) print > "high.txt";
> else if($4~/Yellow|[Gg]reen/) print > "midle.txt";
> else print > "low.txt" }' grade.txt
如果记录中的第 4 个域($4)匹配 Brown.*或者 Black,就将该记录重定位 到文件 high.txt 中,如果匹配 Yellow 或者[Gg]reen,就重定位到 midle.txt 中,否则统 统重定位到 low.txt 中
例子8 统计
将所有孩子的分数累积起来并打印出来
awk '{sum+=$6} END{print sum}' grade.txt
END 表示紧跟其后的语句只会在 awk 处理完所有行之后才被执行
例子9 统计各个级别的人数
awk 'NR!=1 {a[$4]++;}
> END{for(i in a) print i","a[i];}' grade.txt
$4 是级别名称,例如 Yellow、Brown 等,a 是一个以这些级别为下标的数组, 其值从零开始计算
awk脚本
想象我现在要打印出整个班级的所有孩子的信息,而且在最前面把表头也打印出来, 而且下面要打印一行“===========”来跟具体内容加以划分。并且在最后一行,统 计孩子们的平均年龄以及平均分数。将 awk语句组织成脚本,如下:
1 #!/usr/bin/awk -f #-f 表示运行该脚本需要指定一个文件作为输入
2
3 BEGIN{ #awk 开始运行之前的准备工作
4 age = 0
5 score =
6 }
7 {
8 if(NR==1) #打印表头已经分割线
9 {
10 print $0
11 printf "=============" #由于是 printf,没有\n 就不换行
12 print "=============" #由于是 print,会自动换行
13 }
14 else
15 {
16 age+=$5
17 score+=$6
18 print $0
19 }
20 }
21 END{ #awk 处理完所有的记录之后,END 才开始运行
22 printf "======================"
23 print "======================"
24 print "Average:\t\t\t\t\t"age/NR ",\t" score/NR
25 }