上一篇文章我们简单举了几个例子了解了一下awk命令的基本语法,这里,再次贴出来这个命令的基本语法,如下:
awk基本语法:
awk [option] 'pattern{action}' file1,file2,...filen
其中action中最常用的print命令。通过上一篇文章我们知道option当中包含的是awk命令的一些参数,pattern当中包含的BEGIN和END等awk模块,action当中包含的是awk命令当中的动作,这篇文章介绍awk的其他一些特征。
01
awk脚本
awk命令也经常用来写一些脚本,这些脚本的格式如下:
脚本格式
awk 'BEGIN{ commands } pattern{ commands } END{ commands }' file
下面简单介绍下awk执行脚本的过程:
BEGIN { commands } pattern
语句块中的语句
BEGIN语句块:在awk开始从输入输出流中读取行之前执行,在BEGIN语句块中执行如变量初始化,打印输出表头等操作。pattern{ commands }
语句块。它逐行扫描文件,从第一行到最后一行重复这个过程,直到全部文件都被读取完毕。
pattern语句块:pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行。{ }
类似一个循环体,会对文件中的每一行进行迭代,通常将变量初始化语句放在BEGIN语句块中,将打印结果等语句放在END语句块中。END { command }
语句块
END语句块:在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。下面我们来看一个awk脚本的例子:
[root@dev01 yeyz_shell]# vim score.txt
[root@dev01 yeyz_shell]# cat score.txt
Marry
Jack
Tom
Mike
Bob
[root@dev01 yeyz_shell]# vim awk.txt
[root@dev01 yeyz_shell]# cat awk.txt
#!/bin/awk -f
#运行前
BEGIN {
math =
english =
computer =
printf "NAME NO. MATH ENGLISH COMPUTER TOTAL\n"
printf "---------------------------------------------\n"
}
#运行中
{
math+=$3
english+=$4
computer+=$5
printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
printf "---------------------------------------------\n"
printf " TOTAL:%10d %8d %8d \n", math, english, computer
printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
[root@dev01 yeyz_shell]# awk -f awk.txt score.txt
NAME NO. MATH ENGLISH COMPUTER TOTAL
---------------------------------------------
Marry
Jack
Tom
Mike
Bob
---------------------------------------------
TOTAL:
AVERAGE: 63.80 78.60 70.00
[root@dev01 yeyz_shell]#
上面的例子中,我们首先构造一个数据源文件score.txt,然后定义一个awk脚本awk.txt文件,这个脚本给源文件首尾都加上了一些标志,这些标志当中使用格式控制符对输出的格式进行控制,最终输出结果如上代码段所示。
02
格式化输出
上面的脚本当中使用了诸如%10d等格式化输出的符号,这里我们对这些符号进行一定的解释,格式化输出的时候,一般使用printf函数,而不是print方法,这里我们看一种格式化输出方法:
[root@dev01 yeyz_shell]# cat awk_test5.txt
aaa bbb ccc
xxx yyy zzz
uuu vvv www
[root@dev01 yeyz_shell]# awk '{printf "第一列: %s\n",$1}' awk_test5.txt
第一列: aaa
第一列: xxx
第一列: uuu
[root@dev01 yeyz_shell]# awk '{printf "第一列: %s 第二列 : %s\n",$1,$2}' awk_test5.txt
第一列: aaa 第二列 : bbb
第一列: xxx 第二列 : yyy
第一列: uuu 第二列 : vvv
[root@dev01 yeyz_shell]#
03
pattern模式详解
awk命令中的pattern模式不仅仅有BEGIN和END两种,还有一些其他的模式,这里举例子进行说明:
[root@dev01 yeyz_shell]# cat awk_test6.txt
this is line
this is line
this is line
this is line
this is line
打印出行号等于的行
[root@dev01 yeyz_shell]# cat awk_test6.txt | awk 'NR==5{print $0}'
this is line
打印出行号大于的行
[root@dev01 yeyz_shell]# cat awk_test6.txt | awk 'NR>3{print $0}'
this is line
this is line
打印出第一列是的行
[root@dev01 yeyz_shell]# cat awk_test6.txt | awk '$1==3{print $0}'
this is line
通过上述例子我们可以看到,awk命令中的模式可以写成一些条件表达式,例如NR==5,NR>3,$1==3等等,如果我们在模式处不写任何东西,那就变成了我们最常用的那种awk '{print $1,$2}',这种类型的语句我们也可以任务它有模式,只不过它的模式是空而已。至此,我们见过的模式包含以下三种:
空模式
BEGIN/END模式
条件表达式模式
接下来,介绍另外一种模式,即正则模式,正则模式跟正则表达式有一定的关系,正则模式下的awk命令的语法如下:
awk ‘/正则表达式/{print $0}’ filename
话不多说,我们还是通过例子来看。
[root@dev01 yeyz_shell]# cat awk_test7.txt
hello,word
this is a shell program
This is a handsome boy
I am a DBA
找出包含and的行,并打印它的第一列
[root@dev01 yeyz_shell]# cat awk_test7.txt | awk '/and/{print $1 }'
This
找出包含a的行,并打印它的第一列
[root@dev01 yeyz_shell]# cat awk_test7.txt | awk '/a/{print $1 }'
this
This
I
上面的例子描述了如何通过正则匹配出包含某个关键字的行,并打印这一行的某一列值,当然,有一些例子存在例外,比如下面这个:
[root@dev01 yeyz_shell]# cat awk_test8.txt
/usr/local/mysql
/bin/bash
/etc/profile
[root@dev01 yeyz_shell]# cat awk_test8.txt | awk '//bin/bash/{print $1}'
awk: //bin/bash/{print $1}
awk: ^ syntax error
[root@dev01 yeyz_shell]# cat awk_test8.txt | awk '/\/bin\/bash/{print $1}'
/bin/bash
[root@dev01 yeyz_shell]#
当我们使用/bin/bash来匹配的时候,我们发现语法报错,原因是这个文件中包含的都是路径,而带/的字符串匹配的时候会和正则表达式前后的/产生冲突,也就是/正则表达式/这种格式中,正则表达式中不能出现/,如果出现,需要使用\/进行转义。
正则匹配模式还包含很多,没有办法全部罗列,后续有应用的时候再去查询吧,常用的一些方法记住就足够应对一般的应用场景了。
04
条件语句
了解了匹配模式,现在我们再来看看条件语句。条件语句,顾名思义就是在awk命令中加入if else这种条件判断语句,具体怎么去加,我们还是通过例子来看:
[root@dev01 yeyz_shell]# cat awk_test9.txt
hello world
good good study
I love you very much
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{if(NR="hello"){print $2}}'
world
good
love
如果某一行第一列是hello,则输出该行第二列的值
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{if($1=="hello"){print $2}}'
world
如果某一行第一列是hello,则输出该行第二列的值,否则输出该行的所有列
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{if(NR==3){print $2} else {print $0}}'
hello world
good good study
love
输出第三行的第二列
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{if(NR==3){print $2}}'
love
05
内置函数
awk中包含很多内置函数,这些内置函数如果使用的比较熟练,可以有很大的作用,这里简单列举几个内置函数的用法:
substr函数
substr(s,p) 返回字符串s中从p开始的后缀部分
substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分
[root@dev01 yeyz_shell]# cat awk_test9.txt
hello world
good good study
I love you very much
拿到第一行的字符串
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{if(NR==1){print $0}}'
hello world
拿到第一行的字符串,然后打印第二列第三个字母开始到字符串末尾 world-->rld
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{if(NR==1){print $0}}' | awk '{print substr($2,3)}'
rld
拿到第一行的字符串,然后打印第二列第三个字母开始,连续打印两个字符 world-->rl
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{if(NR==1){print $0}}' | awk '{print substr($2,3,2)}'
rl
split 分割函数
split是一个分割函数,它的基本用法是:
split (string, array, field separator) split (string, array) -->如果第三个参数没有提供,awk就默认使用当前FS值
[root@dev01 yeyz_shell]# var="10:11:12"
[root@dev01 yeyz_shell]# echo $var | awk '{split($0,a,":");print a[1],a[2],a[3]}'
length函数
输出文本的长度,举例如下:
echo "123" | awk '{print length}'
[root@dev01 yeyz_shell]# cat awk_test9.txt
hello world
good good study
I love you very much
输出每一行的长度
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{print length}'
输出每一行第一列单词的长度
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '{print length($1)}'
gsub替换函数
gsub函数则使得在所有正则表达式被匹配的时候都发生替换。它的基本语法为: gsub(src, dst, target string); 简称 gsub(r,s,t)。
[root@dev01 yeyz_shell]# cat awk_test9.txt
hello world
good good study
I love you very much
将文本中所有包含good的列当中的good改为bad
[root@dev01 yeyz_shell]# cat awk_test9.txt | awk '$0 ~ /good/ {gsub("good", "bad", $0); print $0}'
bad bad study