共计 3698 个字符,预计需要花费 10 分钟才能阅读完成。
文本三剑客—-awk(3)
awk 简介
awk 是一个强大的文本分析工具,与 grep(查找)、sed(编辑)一并称为“文本处理三剑客”。awk 最强大的功能是对数据分析并生成报告。
awk 有 3 个不同版本: awk、nawk 和 gawk,未作特别说明,一般指 gawk,gawk 是 AWK 的 GNU 版本。
awk 其名称得自于它的创始人 Alfred Aho、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。awk 能读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
工作原理
一次读取一行文本,按输入分隔符进行切片,切成多个组成部分,将每片直接保存在内建的变量中,$1,$2,$3….,引用指定的变量,可以显示指定断,或者多个断。如果需要显示全部的,需要使用 $0 来引用。可以对单个片断进行判断,也可以对所有断进行循环判断。其默认分隔符为空格
- 按行读取文本(文件的每一行称为记录)
- 按输入分隔符进行切片
- 对切片自动生命变量 $1,$2…(域标识;$0 为所有域)
- 对指定目标做处理(处理及打印等)
语法格式
awk [options]‘program’FILE……
[options]
–F:指明输入时的分隔符
–v:自定义变量
–f:调用 awk 脚本
program:pattern{action statements;..}
-pattern:触发条件
-action statements:对数据处理动作
步骤
- 执行 BEGIN{action;…}
BEGIN 在输入之前执行,通常用来打印表头,变量初始化。 - 读取,执行 pattern{action;…}
默认执行{print} - 执行 END{action;…}
读取到打印结束后执行,通常用作分析结果,信息汇总。
变量
内置变量
- FS:输入字段分隔符
- OFS:输出字段分隔符
- RS:输入记录分隔符
- ORS:输出记录分隔符
- ARGC:命令行参数的个数
- ARGV:数组,保存命令行给定的各参数
- NF:字段数量
- NR:行号
- FNR:个文件分别计数,行号
- FILENAME:当前文件名
自定义变量
- 选项位置定义:-v var=hello
- 在 program 中定义:awk‘BEGIN{test=”hello”;print test}’
字符串处理
- length([s]):返回指定字符串的长度
- sub(r,s,[t]):对 t 字符串进行搜索 r 表示的模式匹配的内容,并将第一个匹配的内容替换为 s
echo“2008:08:08 08:08:08″ | awk‘sub(/:/,”-“,$0)’ - gsub(r,s,[t]):对 t 字符串进行搜索 r 表示的模式匹配的内容,并全部替换为 s 所表示的内容
echo“2008:08:08 08:08:08″ | awk‘gsub(/:/,”-“,$0)’ - split(s,array,[r]):以 r 为分隔符,切割字符串 s,并将切割后的结果保存至 array 所表示的数组中,第一个索引值为 1, 第二个索引值为 2,…
netstat -tan | awk‘/^tcp>/{split($5,ip,”:”);count[ip[1]]++} END{for (i in count) {print i,count[i]}}’
Printf 命令
- print 不需要指定,printf 需要 指定 format
- printf 后面的字串需要使用 双引号
- 字串定义后的内容需要 使用”,”分隔,后面直接跟 Item1,item2….
- format 用于指定后面的每个 item 的输出格式
- printf 语句不会自动打印 换行符 \n
格式符
- %s: 显示字符串
- %d,%i: 显示十进制整数
- %e,%E: 科学计数法数值显示
- %f: 显示为浮点数
- %g,%G: 以科学数法或浮点形式显示数值
- %c: 显示字符的 ASCII 码
- %u: 无符号整数
- %%: 显示 % 号自身,相当于转义
修饰符
- N: 显示宽度
- -: 左对齐(默认为右对齐)
- +: 显示数值符号
操作符
- 算数
x+y, x-y, x*y, x/y, x^y, x%y - 赋值
=, +=, -=, *=, /=, %=, ^=,++, — - 比较
==, !=, >, >=, <, <= - 模式匹配符
~:左边是否和右边匹配包含!~:是否不匹配 - 逻辑
&&,||,!
awk -F:‘{printf“Username: %-15s,UID:%d\n”,$1,$3}’/etc/passwd
PROGRAM
pattern
- )默认匹配每一行
- )/pattern/:仅处理匹配到的行
- )/pattern1/,/pattern2/:处理 pattern1 到 pattern2 之间
- )关系表达式:真:非 0 假:空或 0
action
- )Expressions: 算术,比较表达式等
- )Control statements:if, while 等
- )Compound statements:组合语句
- )input statements
- )output statements:print 等
控制语句
- if-else
awk‘BEGIN{test=100;if(test>90){print“very good”} else if(test>60){print“good”}else{print“no pass”}}’
成绩为 100;大于 90 打印“very good”;大于 60 打印“good”;其余打印“no pass” - while 循环
条件”真”,进入循环;条件”假”,退出循环
awk‘/^[[:space:]]*Linux16/{i=1;while(i<=NF) {if(length($i)>=10){print $i,length($i)}; i++}}’/etc/grub2.cfg
以空白符开头后跟”Linux16″的行中,把字符数大于 10 的字符串打印出来。 - do-while 循环
无论真假,至少执行一次
awk‘BEGIN{sum=0;i=0;do{sum+=i;i++;}while(i<=100);print sum}’
累加 - for 循环
遍历
awk‘/^[[:space:]]*Linux16/{for(i=1;i<=NF;i++) {print$i,length($i)}}’/etc/grub2.cfg - switch 语句
- break 和 continue
awk‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i%2==0)continue;sum+=i}print sum}’
awk‘BEGIN{sum=0;for(i=1;i<=100;i++){if(i==66)break;sum+=i}print sum}’ - next
提前 结束对本行处理而直接进入下一行处理
seq {1,20} | awk -F:‘{if($1%2==0)next ; print $1}’
打印奇数行
数组
- )可使用任意字符串;字符串要使用双引号括起来
- )如果某数组元素事先不存在,在引用时,awk 会自动创建此元素,并将其值初始化为“空字符串(即为”假”)”
- 若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
示例练习:
[root@localhost ~]# awk -F: '$NF ~ /bash$/{print $1,$NF}' /etc/passwd
root /bin/bash
wang /bin/bash
lao /bin/bash
cai /bin/bash
[root@localhost ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash
wang /bin/bash
lao /bin/bash
cai /bin/bash
[root@localhost ~]# cat f
aa
bb
cc
dd
aa
bb
cc
dd
[root@localhost ~]# awk '!arr[$0]++' f
aa
bb
cc
dd
[root@localhost ~]# awk '{!arr[$0]++;print $0,arr[$0]}' f
aa 1
bb 1
cc 1
dd 1
aa 2
bb 2
cc 2
dd 2
[root@localhost ~]# awk '/^UUID/||/^\/dev/{fs[$3]++} END{for (i in fs){print i,fs[i]}}' /etc/fstab
swap 1
xfs 4
[root@localhost ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab
man 1
and/or 1
maintained 1
xfs 4
Accessible 1
Thu 1
UUID=63af8e82-3a2a-40ed-8f76-64f56502ee1c 1are 1
defaults 4
blkid(8) 1
/ 1
/dev/mapper/cl-root 1
0 10
[root@localhost ~]# echo "Yd$C@M05MB%9&Bdh7dq+YVixp3vpw" | awk -F "[^[:digit:]]" '{for(k=1;k<=NF;k++){a[$k]}} END{for(i in a) {printf"%s",i}printf"\n"}'
79053