linux之awk命令详解
AWK是一种优良的文本处理工具。它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一。
AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。
它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言,
它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
最简单地说, AWK 是一种用于处理文本的编程语言工具。AWK 在很多方面类似于 shell 编程语言,
尽管操作可能会很复杂,但命令的语法始终是:
awk '{pattern + action}' 或者 awk 'pattern {action}'
其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号 ({}) 不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。
awk提供了一个完整的编程模型。
awk程序由一个主输入循环维持。并且反复执行。直到终止条件被触发。
但是这些处理都是由awk自己完成的。我们只需要编写循环中的处理。
会循环的处理pattern匹配的每一条数据,直到处理完毕。
awk中还定义了两个特殊的字段。BEGIN和END。BEGIN用于在主输入循环之前执行。即在未读取输入文件之前执行。END则相反,
用于在主输入循环之后执行。即在读取输入文件执行完毕后执行。
awk的调用方法也分为三种:
①awk [-F 域分隔符] 'awk程序段' 输入文件
②awk -f awk脚本文件 输入文件
③./awk脚本文件 输入文件(awk脚本需要以'#!'开头加上awk的路径,并且设置为可执行)
可以看到,第一种方式中,可以通过-F来指定域分隔符。那这是什么意思呢?
在awk中认为输入文件是结构化的,awk将每个输入文件行定义为记录。行中的每个字符串定义为域,域之间用空格,tab键或其他字符进行分割,分割的符号叫做分隔符。多个连续的空格或tab键被当作一个分隔符来处理。
在awk中定义了一个域操作符$来指定执行动作的域。域操作符后面跟数字或变量来标识域的位置。域的编号从1开始,0表示所有的域。
比如:zhangsan 男 24 江西 138xxxxxxxx
上面这条记录中,$0就代表了整条记录,$1就代表[zhangsan],$2就代表[男]。
尽管-F可以改变分隔符,但是在awk中还提供了一种更方便的方式来改变分隔符。就是awk环境变量FS。
我们可以通过在BEGIN字段中设置FS的值来改变分隔符。
下面就来简单体验下awk的简单使用:
[fuwh@localhost 12:42 ~/stu]$ cat tx fuwh men:jiangxi zhangsan girl:shanghai [fuwh@localhost 12:45 ~/stu]$ awk '{print $2}' tx men:jiangxi girl:shanghai [fuwh@localhost 12:46 ~/stu]$ awk -F":" '{print $2}' tx jiangxi shanghai [fuwh@localhost 12:47 ~/stu]$ awk 'BEGIN {FS=":"} {print $1}' tx fuwh men zhangsan girl [fuwh@localhost 12:48 ~/stu]$
awk既然也是一种编程语言,那里面肯定也是有很多普通语言所具有的运算符,循环,判断之类的。
在awk中awk程序段都是由模式和动作组成的。模式是一组用于测试输入行是否需要执行动作的规则,动作包含语句,函数和表达式的执行过程,在模式匹配中,经常需要用到正则表达式。awk支持'?'和'+'这两个元字符。
关系和布尔运算符
关系运算符主要用于awk模式匹配
<:小于
>:大于
<=:小于或等于
>=:大于或等于
==:等于
!=:不等于
~:匹配正则表达式
!~:不匹配正则表达式
布尔运算:
||:逻辑或
&&:逻辑与
!:逻辑非
例子:
[fuwh@localhost 13:31 ~/stu]$ cat tx fuwh:men:jiangxi zhangsan:girl:shanghai lisi:girl:beijing wangwu:feman:shenzhen [fuwh@localhost 13:31 ~/stu]$ awk 'BEGIN{FS=":"} {if($2=="men"||$2~/girl/) print $3}' tx jiangxi shanghai beijing [fuwh@localhost 13:34 ~/stu]$
表达式
在awk中也可以定义变量,一个表达式可以包含赋值,运算符等等。
+:加
-:减
*:乘
/:除
%:模
^或**:乘方
++x:自增,在返回x之前
x++:自增,在返回x之后
例子:
[fuwh@localhost 14:06 ~/stu]$ cat tx fuwh:men:jiangxi zhangsan:girl:shanghai lisi:girl:beijing wangwu:feman:shenzhen [fuwh@localhost 14:10 ~/stu]$ awk 'BEGIN{FS=":"} {if($2=="girl") x++} END{print "女生个数:" x}' tx 女生个数:2 [fuwh@localhost 14:10 ~/stu]$
系统变量
在awk中,还内建了许多变量,用来设置环境信息 。叫做系统变量。
系统变量分为两种:一种是用于改变awk的默认值,如域分隔符FS,第二种用于定义系统值。在处理文本的时候可以读取这些系统值,如记录中的域数量,当前记录数,当前文件名之类的。
下面是一些常见的环境变量及其意义:
$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函数所匹配的字符串的第一个位置
SUBSEP:数组下标分隔符,默认是\034
例子:
[fuwh@localhost 14:31 ~/stu]$ cat tx fuwh:men:jiangxi zhangsan:girl:shanghai lisi:girl:beijing wangwu:feman:shenzhen [fuwh@localhost 14:31 ~/stu]$ awk 'BEGIN{FS=":"} {print "第"NR"条记录"} END{print FILENAME "共"FNR"条记录,每条有"NR"个域"}' tx 第1条记录 第2条记录 第3条记录 第4条记录 tx共4条记录,每条有4个域 [fuwh@localhost 14:32 ~/stu]$
格式化输出
前面我们都是用print进行输出,但是,在awk中,还提供了printf这个输出来进行格式化的输出工作。
基本语法:
printf (格式控制符,参数)
printf的语句分为两部分,第一部分是格式控制符,都以%开始,用以描述格式规范,第二部分是参数列表,比如变量名列表。与格式控制符相对应。
格式控制符又可以分为修饰符和格式符两种。
修饰符:
-:左对齐
width:域的步长
-prec:小数点右边的位数
格式符:
%c:ASCII字符
%d:整型数
%e:浮点数,科学计数法
%f:浮点数
%o:八进制数
%s:字符串
%x:十六进制数
例子:
[fuwh@localhost 14:35 ~/stu]$ cat tx fuwh:men:jiangxi zhangsan:girl:shanghai lisi:girl:beijing wangwu:feman:shenzhen [fuwh@localhost 14:46 ~/stu]$ awk 'BEGIN{FS=":"}{printf("%s\t%s人\n",$1,$3) }' tx fuwh jiangxi人 zhangsan shanghai人 lisi beijing人 wangwu shenzhen人 [fuwh@localhost 14:47 ~/stu]$
内置字符串函数
在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(s,t):在t上将r分成序列s
sub(r,s,t):将t中第一次出现的r替换成s
substr(r,s):返回字符串r中从s开始的后缀部分
例子:
[fuwh@localhost 14:59 ~/stu]$ cat tx fuwh:men:jiangxi zhangsan:girl:shanghai lisi:girl:beijing wangwu:feman:shenzhen [fuwh@localhost 15:03 ~/stu]$ awk 'BEGIN{FS=":"}{if($1=="fuwh") print(length($3))}' tx 7 [fuwh@localhost 15:04 ~/stu]$
向awk脚本传递参数
在awk中使用的变量,可以在命令行中进行赋值。实现向awk脚本传递参数。变量复制放在脚本之后、输入文件之前,格式为:
awk 脚本 parameter=value 输入文件
例子:
[fuwh@localhost 15:26 ~/stu]$ ll tx* -rw-rw-r--. 1 fuwh fuwh 80 8月 14 13:31 tx -rwxrw-r--. 1 fuwh fuwh 41 8月 14 15:26 tx.awk [fuwh@localhost 15:26 ~/stu]$ cat tx tx.awk fuwh:men:jiangxi zhangsan:girl:shanghai lisi:girl:beijing wangwu:feman:shenzhen #!/bin/awk -f {printf("%s\t%s\n",$1,$3)} [fuwh@localhost 15:26 ~/stu]$ ./tx.awk FS=":" tx fuwh jiangxi zhangsan shanghai lisi beijing wangwu shenzhen [fuwh@localhost 15:26 ~/stu]$
条件语句和循环语句
awk中支持下面几种条件语句和循环语句。
if(条件表达式)
动作1
[else
动作2]
while(条件表达式)
动作
do
动作
while(条件表达式)
for(计数器初始值;测试计数器条件;计数器变化)
动作
数组
数组的索引可以是数字,也可以是字符串,索引并不表示存储的顺序信息。在awk中,会自动维护一对索引和值的信息。
awk中访问数组的所有元素:
for(变量 in 数组名)
xxxxx
还可以使用in来判断是否在数组中存在
索引名 in 数组名
如果存在,则返回1,不存在则返回0