1.概述
-
awk语言可以从文件或字符串中基于指定规则浏览和抽取信息,在抽取信息的基础上,才能进行其他文本操作
-
awk程序有一个主输入循环(main input loop)维持,主输入循环反复执行,直到终止条件被触发
主输入循环自动依次读取输入文件行,以供处理,而处理文件行的动作为用户定义
-
awk定义了连个特殊的字段:BEGIN和END
- BEGIN用于在主输入循环之前执行,即在未读取输入文件行之前执行
- END用于在主输入循环之后执行,即在读取输入文件行完毕后执行
-
awk编程模型分为三个阶段:
- 读输入文件之前的执行代码段(由BEGIN关键字标识)
- 读取输入文件时的执行代码段
- 读输入文件完毕之后的执行代码段(由END关键字标识)
-
awk调用方法
-
在shell命令行输入命令调用awk
awk [-F域分隔符] 'awk程序段' 输入文件
-
将awk程序段插入脚本文件,然后通过awk命令调用它
awk -f awk脚本文件 输入文件
-
将sed命令插入脚本文件后,设置该脚本文件为可执行,然后直接执行该脚本文件
-
2.awk编程
-
任何awk语句都由模式(pattern)和动作(action)组成
-
模式是一组用于测试输入行是否需要执行动作的规则
模式决定动作何时触发和触发事件
-
动作是包含语句、函数和表达式的执行过程
动作执行对输入行的处理
-
2.1 awk模式匹配
awk '/^$/{print "This is a blank line."}' input_file
# 一旦匹配到空行,就执行打印操作
- 单引号中间是awk程序段
- ^$部分是模式
- 花括号部分是动作
- 模式和动作以/符号分隔
2.2 记录和域
-
awk将每个输入文件行定义为记录(Records)
-
行中的每个字符串定义为域(Fields)
-
域之间用空格、Tab键或其他符号进行分隔,分隔域的符号叫做分隔符
-
awk定义域操作符(来指定执行动作的域,域操作符)后面跟数字或变量来标识域的位置,每条记录的域从1开始编号,如$1表示第1个域,$2表示第2个域,$0表示所有的域。
awk '{print $2,$4,$1,$3,$0}' inputfile
-
域操作符$后面还可以跟变量,或者变量运算表达式
awk 'BEGIN {one=1;two=2} {print $(one+two)}' inputfile # 其中$(one+two)等价于$3
-
用awk的-F选项可以改变分隔符
awk -F"/t" '{print $3}' inputfile
-
说明
大写F选项用来改变分隔符,小写-f选项则表示调用awk脚本
-
-
-
改变分隔符
-
-F选项
-
使用awk环境变量FS,即通过在BEGIN字段中设置FS的值来改变分隔符
awk 'BEGIN {FS=" "} {print $0}' inputfile
-
可以使用正则表达式将分隔符设置为多个字符
FS=" +"
-
-
2.3 关系和布尔运算符
-
awk定义了一组关系运算符用于awk模式匹配
运算符 意义 < 小于 > 大于 <= 小于等于 >= 大于等于 == 等于 != 不等于 ~ 匹配正则表达式 !~ 不匹配正则表达式 -
awk布尔运算符及其意义
运算符 意义 || 逻辑或 && 逻辑与 ! 逻辑非 -
示例
# 第1域匹配root awk 'BEGIN {FS=":"} $1~/root/' /etc/passwd # 全部域匹配root awk 'BEGIN {FS=":"} $0~/root/' /etc/passwd # 全部域不匹配root awk 'BEGIN {FS=":"} $0!~/root/' /etc/passwd # 第3域值小于第4域值 awk 'BEGIN {FS=":"} {if($3<$4) print $0}' /etc/passwd
2.4 表达式
awk表达式用于存储、操作和获取数据,一个awk表达式可由数值、字符常量、变量、操作符、函数和正则表达式自由组合而成。
-
变量
- 变量是一个值的标识符
- 定义一个变量只需要定义一个变量名并将值赋给它即可
- 变量名只能包含字母、数字和下划线,不能以数字开头
- awk变量名区分大小写
- 定义awk变量无须声明变量类型,每个变量有两种类型的值:字符串值和数值,awk根据表达式上下文来确定使用哪个值
- 变量的默认值为0、默认字符串值为空
-
awk算术运算符及其意义
运算符 意义 + 加 - 减 * 乘 / 除 % 模 ^或** 乘方 ++x 在返回x值之前,x变量加1 x++ 在返回x值之后,x变量加1
2.5 系统变量
-
定义
awk定义了很多内建变量用于设置环境信息,称为系统变量
-
系统变量分类
- 用于改变awk的默认值,如域分隔符
- 用于定义系统值,在处理文本时可以读取这些系统值,如记录中的域数量、当前记录数、当前文件名等。
-
说明
awk动态改变第2种系统变量的值
-
-
awk环境变量及其意义
变量名 意义 $n 当前记录的第n个域,域间由FS分隔 $0 记录的所有域 ARGC 命令行参数的数量 ARGIND 命令行中当前文件的位置(以0开始标号) ARGV 命令行参数的数组 CONVFMT 数字转换格式 ENVIRON 环境变量关联数组 ERRNO 最后一个系统错误的描述 FIELDWIDTHS 字段宽度列表,以空格键分隔 FILENAME 当前文件名 FNR 浏览文件的记录数 FS 字段分隔符,默认是空格键 IGNORECASE 布尔变量,如果为真,则进行忽略大小写的匹配 NF 当前记录中的域数量 NR 当前记录数 OFMT 数字的输出格式 OFS 输出域分隔符,默认是空格键 ORS 输出记录分隔符,默认是换行符 RLENGTH 由match函数所匹配的字符串长度 RS 记录分隔符,默认是空格键 RSTART 由match函数所匹配的字符串的第1个位置 SUBSEP 数组下标分隔符,默认值是 34
2.6 格式化输出
awk的一大主要功能是产生报表,报表要求按照预定的格式输出。
printf输出语句,可以规定输出的格式。
-
printf的基本语法
printf (格式控制符,参数)
-
格式控制符
格式控制符,以%符号开始,用以描述格式规范
格式控制符分为awk修饰符和格式符两种:
-
awk修饰符
修饰符 意义 - 左对齐 width 域的步长 -prec 小数点右边的位数 -
格式符
格式符 意义 %c ASCII字符 %d 整数型 %e 浮点数,科学记数法 %f 浮点数 %o 八进制数 %s 字符串 %x 十六进制数
-
-
参数列表
与格式控制符相对应,是输出的对象
-
示例
# No.1 参数为列表形式 awk 'BEGIN {FS=":"} {printf("%s %d ",$1,$3)}' /etc/passwd # No.2 转换ASCII awk 'BEGIN {printf("%c ",65)}' # No.3 # .prec表示输出小数点后的位数,浮点数长度控制在10位,2位小数点 # 右对齐(printf的默认对其方式) awk 'BEGIN {printf("%10.2f ",2020.1234)}' # No.4 # printf修饰符-和width的用法 #对第1个%s进行了修饰,-15表示该字符串长度控制为15位,并且左对齐,若字符串不足15位,则用空格补全 awk 'BEGIN {FS=":"} {printf("%-15s %s ",$1,$3)}' /etc/passwd # No.5 # 要在输出的域顶部加上解释语言,可以在BEGIN字段中添加相应的输出注释 awk 'BEGIN {FS=":";print "用户名 用户编号"} {printf("%-15s %s ",$1,$3)}' /etc/passwd # No.6 # 单独使用.prec awk 'BEGIN {printf("%.3f ",2021.0231)}'
-
2.7 内置字符串
awk内置的字符串函数,用于实现文本的字符串替换、查找以及分隔等功能。
-
awk字符串函数及其意义
函数名 意义 gsub(r,s) 在输入文件中用s替换r gsub(r,s,t) 在t中用s替换r index(s,t) 返回s中字符串第一个t的位置 length(s) 返回s的长度 match(s,t) 测试s是否包含匹配t的字符串 split(r,s,t) 在t上将r分成序列s sub(r,s,t) 将t中第1次出现的r替换为s substr(r,s) 返回字符串r中从s开始的后缀部分 substr(r,s,t) 返回字符串r中从s开始长度为t的后缀部分 -
示例
# No.1 # 替换第1域上的root字符串 awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,"gridsphere",$1) {print $0}' /etc/passwd # No.2 # 替换全部域上的root字符串 awk 'BEGIN {FS=":";OFS=":"} gsub(/root/,'gridsphere') {print $0}' # No.3 # index和length函数的用法 awk 'BEGIN {print inex("gridsphere","ph")}' awk 'BEGIN {print length("gridsphere")}' # No.4 # match(s,t)中,t可以是一个正则表达式,若匹配成功,返回匹配t的首位置;若不成功,则返回0 # awk默认状态是区分大小写的,系统变量IGNORECASE设为1可忽略大小写 awk 'BEGIN {print match("gridsphere",/D/)}' awk 'BEGIN {IGNORECASe=1;print match("gridsphere",/D/)}' # No.5 # sub(r,s,t)只替换模式出现的第1个位置 awk 'BEGIN {str="multiprocessor programming";sub(/pro/,"PRO",str);printf("%s ",str)}' # No.6 # substr返回字符串的指定后缀 awk 'BEGIN {str="multiprocessor";print substr(str,6)}' awk 'BEGIN {str="multiprocessor";print substr(str,6,7)}'
2.8 向awk脚本传递参数
awk脚本内的变量可以在命令行中进行赋值,实现向awk脚本传递参数;
参数赋值放在脚本之后、输入文件之前:
awk脚本 parameter=value 输入文件
-
注意
awk命令行参数不能被BEGIN字段语句访问,即直到输入文件的第1行被读取时,命令行参数方才生效。
原因:awk读到命令行参数的赋值语句时,并不知道这是一个命令行参数的赋值语句,而认为这是一个文件名,当然这个文件名是无效的,awk继续读取后面的参数,直到一个正确的输入文件名被解析的时候,awk才判定前面的语句是命令行参数的赋值语句。
awk 'BEGIN {print n} {if (n==1) print "Reading the first file!"}' n=1 /etc/passwd
2.9 条件语句和循环语句
-
条件语句
if (条件表达式) 动作1 [else 动作2]
-
循环语句
-
while
while (条件表达式) 动作
-
do while
do 动作 while (条件表达式)
-
for
for (设置计数器初值;测试计数器;计数器变化) 动作
-
2.10 数组
数组是用于存储一系列值的变量,这些值之间通常是有联系的,可以通过索引来访问数组的值,索引需要用中括号括起来。
-
数组的基本格式
array[index]=value
awk数组无须定义数组类型和大小,而可以直接赋值后使用。
# split函数的返回值是数组的大小 # split(r,s,t)函数将字符串以t为分隔符,将r字符串拆分为字符串数组,并存放在t中 awk 'BEGIN {print split("adb/dec/xyz",str,"/")}'