awk命令详解

1、awk介绍

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。
awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。
awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

实现过程

读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,
$0则表示所有域,$1表示第一个域,$n表示第n个域。
默认域分隔符是"空白键" 或 "[tab]键"切开的部分再进行各种分析处理。

使用方法:

awk '{pattern + action}' {filenames}

其中 pattern 表示 awk 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。

花括号{}不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组,指令之间用分号隔开。 pattern就是要表示的正则表达式,用斜杠括起来。

awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。

两者是可选的,如果没有模式,则action应用到全部记录,如果没有action,则输出匹配全部记录。默认情况下,每一个输入行都是一条记录,

但用户可通过RS变量指定不同的分隔符进行分隔。

例如,搜索/etc/passwd有root关键字的所有行

#awk -F: '/root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash

这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。

搜索支持正则,例如找root开头的: 

awk -F: '/^root/' /etc/passwd

2、awk代码框架

'BEGIN{可以进行变量初始化等操作;}
{中间代码区}
END{处理完所有行后,执行此块}'

工作流程:
先执行BEGING,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,
$0则表示所有域,$1表示第一个域,$n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,
最后执行END操作。

3、awk内置变量

ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符

$n 		   当前记录的第n个字段,字段间由FS分隔。
$0 		   完整的输入记录。
ARGIND 		   命令行中当前文件的位置(从0开始算)。
CONVFMT     	   数字转换格式(默认值为%.6g)
ENVIRON 	   环境变量关联数组。
ERRNO 		   最后一个系统错误的描述。
FIELDWIDTHS 	   字段宽度列表(用空格键分隔)。
IGNORECASE 	   如果为真,则进行忽略大小写的匹配。
OFMT 		   数字的输出格式(默认值是%.6g)。
OFS 		   输出字段分隔符(默认值是一个空格)。
ORS 		   输出记录分隔符(默认值是一个换行符)。
RLENGTH 	   由match函数所匹配的字符串的长度。
RSTART 		   由match函数所匹配的字符串的第一个位置。
SUBSEP 		   数组下标分隔符(默认值是\034)。

4、print与printf

两个都是awk打印输出函数
print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

例如:
echo "Hello World" | awk '{print $1, " ", 5}' 

printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

例如:
echo "Hello World" | awk '{printf("%10s,%d\n", FILENAME, 10)}'

5、awk编程

5.1、变量和赋值
除了awk的内置变量,awk还可以自定义变量。 
awk '{BEGIN cnt_line=0;}{cnt_line++;} END{print "cnt_linevalue:", cnt_line}'  input_file
5.2、条件语句、循环语句
awk中的条件语句是从C语言中借鉴来的,见如下声明方式:

if (expression) {
    statement;
    statement;
    ... ...
}

if (expression) {
    statement;
} else {
    statement2;
}

if (expression) {
    statement1;
} else if (expression1) {
    statement2;
} else {
    statement3;
}

5.3、循环语句
awk循环语句支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。

next语句从输入文件中读取一行,然后从头开始执行awk脚本。如:
{
   if ($1 ~/test/){next}
   else {print}
}


exit语句用于结束awk程序,但不会略过END块。退出状态为0代表成功,非零值表示出错。
5.4、awk运算符
运算符 描述
 = += -= *= /= %= ^= **=

赋值

?: C条件表达式
||  或
&&  与
 ~ ~!  匹配正则表达式和不匹配正则表达式
 < <= > >= != ==  关系运算符
空格
连接
+ - * /
加减乘除
^ ***
求幂
++ --
 自增自减
$
 字段引用
in 数组成员

5.5、数组
awk中的数组的下标可以是数字和字母,称为 关联数组

1)用变量作为数组下标
如awk ’{name[x++]=$2}...‘

2)special for遍历
...{for (item in arrayname){print arrayname[item]}}...

3)用字符串作为下标。
如:count["test"]

4)用域值作为数组的下标
如:$ awk '{count[$1]++}

5)delete函数用于删除数组元素
如:$ awk '{line[x++]=$1} END{for(x in line) delete(line[x])}' test。分配给数组line的是第一个
域的值,所有记录处理完成后,special for循环将删除每一个元素

5.6、awk重定向和管道
1)awk可使用shell的重定向符进行重定向输出
如:$ awk '$1 = 100 {print $1 > "output_file" }' test。上式表示如果第一个域的值
等于100,则把它输出到output_file中。也可以用>>来重定向输出,但不清空文件,只做追加操作。

2)输出重定向需用到getline函数
getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容,并给NF,NR和FNR等内建变量赋值。如果得到一条记录,getline函数返回1,如果到达文件的末尾就返回0,如果出现错误,例
如打开文件失败,就返回-1。如:

执行linux的date命令,并通过管道输出给getline,然后再把输出赋值给自定义变量d,并打印它。
$ awk 'BEGIN{ "date" | getline d; print d}' test。

执行shell的date命令,并通过管道输出给getline,然后getline从管道中读取并将输入赋值给d,split函数把变量d转化成数组mon,然后打印数组mon的第二个元素。
$ awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' test。

命令ls的输出传递给geline作为输入,循环使getline从ls的输出中读取一行,并把它打印到屏幕。这里没有输入文件,因为BEGIN块在打开输入文件前执行,所以可以忽略输入文件
awk 'BEGIN{while( "ls" | getline) print}'

在屏幕上打印”What is your name?",并等待用户应答。当一行输入完毕后,getline函数从终端接收该行输入,并把它储存在自定义变量name中。如果第一个域匹配变量name的值,print函数就被执行,END块打印See
you和name的值。
awk 'BEGIN{printf "What is your name?"; getline name < "/dev/tty" } 
$1 ~name {print "Found" name on line ", NR"."} END{print "See you," name "."} test

awk将逐行读取文件/etc/passwd的内容,在到达文件末尾前,计数器lc一直增加,当到末尾时,打印lc的值。注意,如果文件不存在,getline返回-1,如果到达文件的末尾就返回0,如果读到一
行,就返回1,所以命令 while (getline < "/etc/passwd")在文件不存在的情况下将陷入无限循环,因为返回-1表示逻辑真。
awk 'BEGIN{while (getline < "/etc/passwd" > 0) lc++; print lc}'

可以在awk中打开一个管道,且同一时刻只能有一个管道存在。通过close()可关闭管道。awd把print语句的输出通过管道作为linux命令sort的输入,END块执行关闭管道操作
$ awk '{print $1, $2 | "sort" }' test END {close("sort")}

system函数可以在awk中执行linux的命令
$ awk 'BEGIN{system("clear")'

fflush函数用以刷新输出缓冲区,如果没有参数,就刷新标准输出的缓冲区,如果以空字符串为参数,如fflush(""),则刷新所有文件和管道的输出缓冲区。

6、awk的内建函数

6.1、字符串函数
sub函数
匹配记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个
记录。替换只发生在第一次匹配的时候。
格式:
sub (regular expression, substitution string):
sub (regular expression, substitution string, target string)

例如:
在整个记录中匹配,替换只发生在第一次匹配发生的时候。如要在整个文件中进行匹配需要用到gsub
awk '{ sub(/test/, "mytest"); print }' testfile

在整个记录的第一个域中进行匹配,替换只发生在第一次匹配发生的时候
awk '{ sub(/test/, "mytest"); $1}; print }' testfile

gsub函数
作用如sub,但它在整个文档中进行匹配

index函数
返回子字符串第一次被匹配的位置,偏移量从位置1开始
格式:index(string, substring)

返回test在mytest的位置,结果应该是3
awk '{ print index("test", "mytest") }' testfile

length函数
格式:length( string )
length

返回test字符串的长度
awk '{ print length( "test" ) }'

返回testfile文件中每条记录的字符数
awk '{ print length }' testfile

substr函数
返回从位置1开始的子字符串,如果指定长度超过实际长度,就返回整个字符串
格式:substr( string, starting position )
substr( string, starting position, len )

match函数
返回在字符串中正则表达式位置的索引,如果找不到指定的正则表达式则返回0
格式:match( string, regular expression )

打印以连续小写字符结尾的开始位置,这里是11
awk '{start=match("this is a test",/[a-z]+$/); print start}'

toupper和tolower函数
用于字符串大小间的转换,该功能只在gawk中有效
格式:toupper( string )
tolower( string )

split函数
按给定的分隔符把字符串分割为一个数组。如果分隔符没提供,则按当前FS值进行分割
格式:split( string, array, field separator )
  split( string, array )

实例:
awk '{ split( "20:18:00", time, ":" ); print time[2] }'
6.2、时间函数
systime函数
返回从1970年1月1日开始到当前时间(不计闰年)的整秒数
格式:systime( )

strftime函数
使用C库中的strftime函数格式化时间
格式:systime( [format specification][,timestamp] )


awk '{ now=strftime("%m/%d/%y"); print now }'

6.3、内建数学函数


6.4、自定义函数
格式:
function name ( parameter, parameter, parameter, ... ) 
{
statements
return expression  # return statement and expression are optional
}
7、awk传参
awk -v var1=$temp1 -v var2=$temp2 '{......}'  test.txt

















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值