一、awk的基础知识

awk用于数据流
对列和行进行操作
灵活性很强


awk结构
awk 'BEGIN{ print "start" } pattern { commands } END { print "end" }'
三部分,每一部分都可以不出现在脚本。


awk工作方式
1.执行BEGIN
2.从文件或stdin中读取一行,执行pattern,直到文件全部读取完。
3.当读到输入流末尾,执行END语句块。
当第二个模块没有,默认为{ print },打印每一行。


使用不带参数的print时,会打印出当前行。当print的参数是以逗号进行分隔时,参数打印时则以空格作为定界符;awk的print语句中,双引号被当做拼接操作符使用。
# echo |awk '{var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3 ;}'
v1 v2 v3

[root@localhost shell]# echo |awk '{var1="v1"; var2="v2"; var3="v3"; print var1"-"var2"-"var3 ;}'
v1-v2-v3

 

补充内容:
1.awk特殊变量:
NR:表示记录数量,执行过程中对应于当前行号。
NF:表示字段数量,执行过程中对应于当前行的字段数。
$0: 当前行的文本内容。
$1: 第一个字段的文本内容。
$2: 第二个字段的文本内容。

[root@localhost shell]# echo -e "a b c\nd e f\ng h i" |awk '{print "line no:"NR",no of fields:"NF,"$0="$0,"$1="$1,"$2="$2,"$3="$3}'
line no:1,no of fields:3 $0=a b c $1=a $2=b $3=c
line no:2,no of fields:3 $0=d e f $1=d $2=e $3=f
line no:3,no of fields:3 $0=g h i $1=g $2=h $3=i


print $NF 打印出一行中最后的一个字段。$(NF-1)倒数第二个字段

awk '{ print $3,$2 }' file 打印每一行第2和第3个字段
awk 'END{ print NR }' file 统计文件的行数

每行第一个字段值进行累加:
[root@localhost shell]# seq 5 |awk 'BEGIN{ sum=0;print "summation" } { print $1"+"; sum+=$1 } END{ print "=="; print sum }'
summation
1+
2+
3+
4+
5+
==
15

 

2.外部变量值传递给awk
-v
# var=1000
# echo |awk -v a=$var '{print a}'
1000

多个外部变量传递给awk
# var1=1;var2=2
# echo |awk '{print a,b}' a=$var1 b=$var2
1 2

 

3.用getline读取行
getline var
变量var包含了特定行的内容
如果调用不带参数的getline,可以用$0,$1,$2访问文本行的内容
# seq 3 |awk 'BEGIN { getline;print "hahhah",$0 } { print $0}'
hahhah 1
2
3


4.用样式对awk处理的行进行过滤
awk 'NR < 5'   行号小于5的行
awk 'NR==1,NR==4'   行号在1到5之间的行
awk '/linux/'    包含样式linux的行
awk '!/linux/'   不包含样式linux的行


5.设置字段定界符(默认是空格)
awk -F: '{ print $NF }' /etc/passwd 或者
awk 'BEGIN { FS=":" } { print $NF }' /etc/passwd
在BEGIN语句块中可以用OFS="delimiter"设置输出字段的定界符

 

6.从awk中读取命令输出
"command" |getline output; 将command的输出读入变量output


7.在awk中使用循环
for(i=0;i<10;i++) { print &i ; }
或:
for(i in array) { print array[i]; }

awk中的内建字符串控制函数
length(string):返回字符串的长度。

index(string,search_string):返回search_string在字符串中出现的位置。

split(string,array,delimiter):用定界符生成一个字符串列表,并将该列表存入数组。

substr(string,start-position,end-position):在字符串中用字符起止偏移量生成子串,并返回该子串。

sub(regex,replacement_str,string):将正则表达式匹配到的第一处内容替换成replacement_str.

gsub(regex,replacement_str,string):和sub()类似,该函数会替换正则表达式匹配到的所有内容。

match(regex,string):检查正则表达式是否能够匹配字符串。能够,返回非0值。match()有两个特殊变量,RSTART和RLENGTH。变量RSTART包含正则表达式所匹配内容的起始位置,而变量RLENGTH包含正则表达式所匹配内容的长度。

 

 

二、awk的应用

1.打印文件或行中的第n个单词或列
awk '{ print $5 }' file 打印第5列


ls -l |awk '{ print $1 " : " $8 }' < ls -l 打印权限和文件名


2.打印不同行或样式之间的文本
awk 'NR==M, NR==N' file M行到N行

awk '/start/, /end/' file 打印处于start和end之间的文件


3.以逆序形式打印行
tac file1 file2
\n是默认分隔符,-s "分隔符" 指定分隔符

awk实现
[root@localhost shell]# seq 5 | \
> awk '{ lifo[NR]=$0; lno=NR } END{ for(;lno>-1;lno--){ print lifo[lno];}}'
5
4
3
2
1

 

4.awk实现head,tail和tac
head读取文件前10行并打印
awk 'NR<=10' file

tail打印文件后10行
awk '{ buffer[NR%10] = $0 } END { for(i=1;i<11;i++) { print buffer[i%10] } }' file

使用了散列技术。数组buffer的索引是由散列函数NR%10决定的,其中变量NR包含了当前行的行号,$0包含了当前的文本行。因此%将所有余数相同的行都映射到一个特定的数组索引中。在END{}语句中,对数组的10个索引进行迭代,并打印出对应的行。