awk介绍:
awk的名称来源于三个开发者的姓名:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,
Linux文本处理三剑客之一。
有多种版本:New awk(nawk),GNU awk(gawk)
现在默认linux系统下日常使用的是gawk,用命令可以查看正在应用的awk的来源(ls -l /bin/awk )
Linux文本处理三剑客:
grep:文本过滤工具(
sed: 文本编辑工具
awk:Linux上的实现gawk,文本报告生成
Awk编程语言用于处理文本文件。Awk在默认情况下,Awk文件的每一行都被视为一个记录。然后Awk记
录进一步分解成一系列的字段。Awk程序就是一系列作用在记录和字段上的”识别-执行”操作语句。
行row:记录record
列column:字段,域field,属性
awk工作原理:
awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成
第一步:执行BEGIN{action;…}语句块中的语句
第二步:从文件或标准输入读取一行,然后执行pattern{action;…}语句块,它逐行扫描文件,
从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块: 在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输入表格的表头等语句通常可以写在BEGIN语句块中,
END语句块: 在awk从输入流中读取完所有的行后才被执行,比如打印所有所有行的分析结果,这里信息汇总都在END语句块中完成,它也是一个可选语句块
pattern语句块: 中的同用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印每一个读取到的行,awk读取的每一行都会执行该语句块
BEGIN语句常用于打印表头
END语句往往用来做汇总
awk基本用法:
awk
基本用法:
awk [options] ‘program’ var=value file…
awk [options] -f programfile var=value file…
awk [options] ‘BEGIN{ action;… } pattern{ action;… } END{ action;… }’ file …
option:
1 | -F 指明输入时用到的字段分隔符 |
基本格式:awk [options] ‘program’ var=value file…
program:pattern{action statement}
其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。
pattern和action:
pattern部分决定动作语句何时触发及触发事件
如:BEGIN,END
action statements对数据进行处理,放在{}内指明
如:print,printf
分隔符、域和记录
awk执行时,由分隔符分隔的字段(域)标记$1,$2…$n成为标识域。$0表示所有域,即整行
文件的每一行成为记录(record)
省略action,则默认执行print $0的操作
awk pattern
根据pattern条件,过滤匹配到的行,再做处理
如果未指定:空模式,匹配每一行
/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
1
2
3awk '/^UUID/{print $1}' /etc/fstab 取出包含UUID的行的第一个域
awk '!/^UUID/{print $1}' /etc/fstab 取出不包含UUID的行的第一个域
relational expression:关系表达式,结果为”真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13awk 'i=1' /etc/passwd 结果为非零值,显示/etc/passwd内容
awk 'i=0' /etc/passwd 结果为零值,不显示/etc/passwd内容
awk 'i=""' /etc/passwd 结果为空,不显示/etc/passwd内容
awk '!(i="")' /etc/passwd 结果不为空,显示/etc/passwd内容
awk -F: '$NF=="/bin/bash"{print $1$NF}' /etc/passwd
显示/etc/passwd文件中Shell为/bin/bash行的用户名和Shell类型
awk -F: '$NF~/bash$/{print $1$NF}' /etc/passwd
显示/etc/passwd文件中以bash结尾行的用户名和Shell类型line ranges:行范围
起始行,结尾行:/pat1/,/pat2/不支持直接给出数字格式
1
2# 显示root开头的行到nobody开头的行之间的用户名
awk -F: '/^root\>/,/^nobody\>/{print $1}' /etc/passwd1
2# 显示第10行到第20行,标准行号并显示用户名
awk -F: '(NR>=10&&NR<=20){print NR,$1}' /etc/passwdBEGIN/END模式
BEGIN{}:仅在开始处理文件中的文本之前执行一次
END{}:仅在文本处理完成之后执行一次
示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 在/etc/passwd文件每一行上都添加USER USERID,并在处理完文本后打印end file
awk -F: '{print "USER USEID\n"$1":"$3}END{print "end file"}' /etc/passwd
awk -F: '{print "USER USEID";print $1″:"$3}END{print"end file"}' /etc/passwd
# 结果为0,条件为假,不显示
seq 10|awk 'i=0'
# 结果不为0,条件为真,显示所有数字
seq 10|awk 'i=1'
# 显示奇数,第一行i为空,!i则为非空,打印该行,第二行i为非空,!i为空则不打印,以此类推
seq 10|awk 'i=!i'
# 显示1,0,1,0…即上例工作原理
seq 10 | awk '{i=!i;print i}'
# 显示偶数
seq 10|awk '!(i=!i)'
# 显示偶数,第一行i已赋值,所以!i为空,不显示
seq 10 |awk -v i=1 'i=!i'
awp操作符:
输出操作符:print、printf
print格式:
print item1,item2,…
要点:
- 逗号分隔符
- 输出的各item可以是字符串,也可以是数值;当前记录的字段、变量或awk的表达式
- 如省略item,相当于打印整行print $0
printf格式:
格式化输出:print “FORMAT”,item1,item2,…
要点:
- 必须指定FORMAT(格式)
- 不会自动换行,需要显示给出换行控制符,\n
- FROMAT中需要分别为后面每个item指定格式符
格式符:与item一一对应
1 | %c 显示字符的ASCII码 |
修饰符:
1 | #[.#] 第一个#控制显示的宽度;第二个#表示小数点后精度,%3.1f |
示例:
1 | # 将/etc/passwd文件中所有用户名作为一个字符串输出 |
awk变量:
变量:内置和自定义变量
内置变量:
- FS:输入字段分隔符,默认为空白字符
- OFS:输出字段分隔符,默认为空白字符
- RS:输入记录分隔符,指定输入时的换行符
- ORS:输出记录分隔符,输出时用指定符号代替换行符
- NF:字段数量
- NR:记录号,相当于行号
- FNR:同时针对多个文件时,分别计数,添加记录号
- FILENAME:当前文件名
- ARGC:命令行参数的个数
- ARGV:数组,保存的是命令行所给定的各参数,参数标号默认从0开始,且第一个参数为awk命令本身
注:引用内置变量不需要加$
示例:
1 | # 以:作为分隔符,显示每行的第一和第三个域,即用户名和UID |
自定义变量(区分字符大小写):
- -v var=value
- 在program中直接定义
注:{}内赋值变量要用;隔开;
{}外赋值变量时,每个变量前都要加-v选项;
示例:
1 | # 在/etc/fstab文件每一行打印hello |
算术操作符:
x+y 加法运算
x-y 减法运算
x*y 乘法运算
x/y 除法运算(可精确到小数点)
x^y 乘方运算
x%y 取余运算
示例:
1 | 计算9/2.2的结果为4.09091 |
字符串操作符:没有符合的操作符,字符串连接
赋值操作符:
=,+=,-=,*=,/=,%=,^=,++,–
示例:
1 | awk 'BEGIN{i=0;print ++i,i }' |
比较操作符:
==,!=,>,>=,<,<=
模式匹配符:
~ :左边是否和右边匹配包含!~:是否不匹配
示例:
1 | # 取/etc/passwd文件中包含root的行中以:为分隔符的第一个域 |
逻辑操作符:
&& 与
|| 或
! 非
注意:这里的&&和||不是shell中的短路与和短路或,而是类似于[test]判断中的-a和-e
示例:
1 | # 取出/etc/passwd文件中UID大于0且小于1000的用户名 |
函数调用:function_name(argu1,argu2…)
条件表达式(三目表达式):
格式:
条件判断式?if-true-expression:if-false-expression
示例:
1 | # 判断/etc/passwd文件中如果UID大于1000,在用户名后标注普通用户,如果UID小于1000,则标注root或系统用户 |
awk循环判断:
if-else语句
语法:if(condition){statement;…}[else statement]
if(condition1){statement1;…}else if(condition2){statement2;…}else{statement3}
使用场景:对awk取得的整行或某个字段做条件判断
示例:
1 | # 打印UID大于等于1000的用户名和UID |
while循环语句
语法:while(condition){statement}
条件为”真”,进入循环;条件为”假”,退出循环
使用场景:
a)对一行内的多个字段之一类似处理时使用
b)对数组中的各元素逐一处理时使用
示例:
1 | # 取出grub2文件中空白开头跟linux16的行,并显示每个字段和每个字段的字符数 |
do-whlie循环语句
语法:do{statement;…}while(condition)
意义:无论真假,至少执行一次循环体
示例:
1 | 计算1到100的数字之和: |
for循环语句
语法:for(expr1;expr2;expr3) {statement;…}
常见用法:
for(variable assignment;condition;iteration process)
{for-body}
特殊用法:能够遍历数组中的元素
语法:for(var in array) {for-body}
示例:
1 | 计算1到100数字之和 |
break和continue
用于循环体中
break:提前结束本轮循环
continue:提前结束本轮循环,而直接进入下一轮判断;
break[N]:提前结束第N层循环,最内层为第一层
continue[N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
示例:
1 | # 计算1到100奇数之和,数字为偶数时跳过,奇数时相加 |
next语句
提前结束对本行处理而直接进入下一行处理(awk自身循环)
awk -F: ‘{if($3%2!=0) next; print $1,$3}’ /etc/passwd
awk数组:
关联数组:array[#]
下标:
a. 可使用任意字符串;字符串要使用双引号括起来
b. 如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为”空串”
示例:
1 | weekdays["mon"]="Monday" |
遍历数组:
使用for循环可遍历数组中的每个元素
格式:for(var in array) {for-body}
注意:var会遍历array的每个索引
示例:
1 | # 显示weekdays[]数组中的每个元素 |
awk函数:
系统内置函数:
数组处理:
rand():返回0和1之间一个随机数,只有和srand()函数配合才生效
示例:
1
2
3
4
5# 返回0和1之间一个随机数
awk 'BEGIN{srand();print rand()}'
# 返回10个0到100之间的随机数
awk 'BEGIN{srand();for(i=1;i<=10;i++)print rand()*100}'
字符串处理:
length([s]):返回指定字符串的长度
sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s
1
2示例:替换字符第一个出现的":"为"-";
echo "2008:08:08 08:08:08" | awk 'sub(/:/,"-",$1)'gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
1
2示例:全局替换字符第一个出现的":"为"-";
echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"-",$0)'split(s,array,[r]):以r为分隔符,切割字符串s,并将切割后的结果保存至array所表示的数组中,
第一个索引值为1,第二个索引值为2,…
自定义函数:
格式:
function name ( parameter, parameter, … ) {
statements
return expression
}
示例: 编写一个awk函数,比较两个数字的大小
1 | cat fun.awk |
awk中调用shell命令:
1 | awk BEGIN'{system("hostname") }' |