Linux之awk
Linux中有三种主要的文本处理工具,分别是grep,sed和awk,其中grep是文本过滤工具,sed是文本行编辑器,awk是报表生成器,今天我们主要来探讨awk。
awk有nawk,gawk等多种版本,现在默认linux系统下的awk是gawk,也就是我们常用的awk,而在linux系统中gawk本身就是awk的链接文件,所以下文所说awk均为gawk。
一.大致功能
awk是一种用于处理文本的编程语言工具,在很多方面类似于shell编程语言,它支持条件判断,数组,循环等各种编程语言中所有可以使用的功能,所以在一定程度上我们可以把awk称为一种脚本语言解释器,由于awk在处理文本的时候一次读取一行,并根据分隔符进行切片,所以awk可以对文本中的特定片段进行各种加工处理,例如计数,运算等
二.用法格式
awk有三种运行方式,分别是以下三种
1.脚本
awk [options] ‘program’ var=value file
2.程序文件
awk [options] -f programfile var=value file
3.命令行
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file
其中的[options]:
-F 指明输入时用到的字段分隔符
-v var=value: 自定义变量赋值
awk的前两种运行方式直接调用文件或脚本,不多做解释,以下重点讨论awk的命令行用法
awk的命令行用法中,其格式由[options],BEGIN,pattern和END组成,其中[options]主要用于定义分隔符和定义变量,BEGIN是第一步仅且只执行一次的动作可以不写,pattern部分决定定动作语句何时触发及触发事件,以及触发什么事件,END是最后一步仅且只执行一次的动作,也可不写。
三.awk工作原理
第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
awk执行时,由分隔符分隔的字段(域)标记$1,$2..$n称为域标识
$0为所有域,注意:和shell中变量$符含义不同
文件的每一行称为记录
省略action,则默认执行 print $0 的操作,也就是打印整个记录
四.变量
awk中变量分为内置变量和自定义变量,自定义变量顾名思义就是我们自己定义的变量,而内置变量则是awk为方便我们的使用为我们提前准备号的变量,在定义变量时,建议在[options]部分定义内置变量
内置变量:
FS:输入字段分隔符,默认为空白字符
OFS:输出字段分隔符,默认为空白字符
RS:输入记录分隔符,指定输入时的换行符,原换行符仍有效
ORS:输出记录分隔符,输出时用指定符号代替换行符
NF:字段数量
NR:行号
FNR:各文件分别计数,行号
FILENAME:当前文件名
ARGC:命令行参数的个数
ARGV:数组,保存的是命令行所给定的各参数
自定义变量:
在awk中定义自定义变量时若在[options]部分则直接用-v var=value(-v a=123)这样的方式定义即可,若在program中定义,需用“;”隔开,由于当value为数值时可以直接定义但value为带空格的字符串时无法识别所以建议在定义变量时用引号将value引起
五.printf/print
print格式: print item1, item2, ...
要点:
(1) 逗号分隔符
(2) 输出的各item可以字符串,也可以是数值;当前记录的字段、变量或awk的表达式
(3) 如省略item,相当于print $0
示例:
awk ‘{print "hello,awk"}'
awk –F: ‘{print}' /etc/passwd
awk –F: ‘{print “wang”}’ /etc/passwd
printf
按照格式输出,书写时先写目标格式,再在后面补上内容
printf格式:printf “FORMAT”, item1, item2, ...
要点:
(1) 由于printf是格式化输出所以必须指定FORMAT
(2) 不会自动换行,需要显式给出换行控制符,\n
(3) FORMAT中需要分别为后面每个item指定格式符
格式符:与item一一对应
%c: 显示字符的ASCII码
%d, %i: 显示十进制整数
%e, %E:显示科学计数法数值
%f:显示为浮点数
%g, %G:以科学计数法或浮点形式显示数值
%s:显示字符串
%u:无符号整数
%%: 显示%自身
修饰符:
#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后精度,%3.1f 表示一个三位的一位小数的浮点数
-: 左对齐(默认右对齐) %-15s 表示这一部分左对齐并去字符宽度为15,不足则空格补齐
+:显示数值的正负符号 %+d
示例:
awk -F: ‘{printf "%s",$1}’ /etc/passwd
awk -F: ‘{printf "Username: %s\n",$1}’ /etc/passwd
awk -F: ‘{printf "Username: %-15s,UID:%d\n",$1,$3}’ /etc/passwd
六.操作符
awk中支持各种操作符
算术操作符:
x+y, x
-y, x*y, x/y, x^y, x%y
-x: 转换为负数
+x: 转换为数值
赋值操作符:
=, +=,
-=, *=, /=, %=, ^=
++, --
逻辑操作符:与&&,或||,非!
比较操作符:
==, !=, >, >=, <, <=
模式匹配符:
~:左边是否和右边匹配(!~:是否不匹配)其中右边要匹配的部分要用“”或者//括起来
awk–F: ‘$0 ~ /root/{print $1}’ /etc/passwd
awk ‘$0~“^root"' /etc/passwd
awk ‘$0 !~ /root/’ /etc/passwd
七.awk action
awk有以下几种常用action
(1) Expressions:算术,比较表达式等
(2) Control statements:if, while等
(3) Compound statements:组合语句
(4) input statements
(5) output statements:print等
由于其他的action在上面都有介绍所以这里主要讲述控制语句而组合语句则是多种action的组合
1.控制语句if-else
if语句常用于对awk取得的某个字段进行条件判断
格式:if(condition1){statement1}else if(condition2){statement2}
else{statement3}
例如:
用awk读取/etc/passwd 输出系统用户和普通用户
awk -F: ‘{if($3>=1000) {printf "Common user: %s\n",$1} else {printf
"root or Sysuser: %s\n",$1}}' /etc/passwd
2.控制语句while
while常用于对同行内多个字段逐一处理和对数组个元素逐一处理
格式:while(condition){statement;…}
例如:
用awk读取/etc/grub2.cfg 输出以任意空格加linux16作为开头的行的所有字段的长度
其中length()是一个awk的内置函数
awk ‘/^[[:space:]]*linux16/{i=1;while(i<=NF){print $i,length($i); i++}}’ /etc/grub2.cfg
3.控制语句for
for语句功能和while基本相同,同样可用于遍历数组
格式:for(variable assignment;condition;iteration process) {for-body}
例如:
用for代替上面的while输出以任意空格加linux16作为开头的行的所有字段的长度
awk ‘/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
4.控制语句break/continue/next
awk中的break和continue同shell脚本中的功能一样,break跳出当前层的循环,continue跳过本次循环直接进入下一次,当然可以在break和continue跟上数字以表示跳出的循环个数,默认为1.而next则是跳出awk本身的循环,即直接进入下一行的循环。
例如:
awk '{for (i=1;i<3;i++){if (i==2){break}else{print i}}}' /etc/passwd这个循环中break直接跳出当前的for循环直接进入下一行的循环,如果把break换成continue则是跳出本次循环,直接进入i=3时的循环然后才进入下一行的循环。如果把break换成next则是直接进入下一行的循环,由于这个awk语句中除了awk本身的循环只有一层循环所以在这条语句中break和next作用相同。
八.数组
awk中数组通常是以字符串为下标的,其余和shell脚本中的数组基本相同
awk的数组一般写在pattern中,以遍历整个文件,然后在END中通过循环输出我们的数组
例如:
计算/etc/passwd中各种默认shell的个数,其中默认shell是这个文件每行的第七个域,在pattern部分直接以默认shell为数组下表,在awk循环遍历整个文件时,每遇到一种shell就在line数组中创建一个对应的下标,并让这个下标对应的值加一,之后每遇到一次都加一,然后在END部分通过for循环遍历输出每个下标及其对应的值,也就是出现的次数
awk -F: ‘{line[$7]++}END{for(i in line){print i,line[i]}}' /etc/passwd