Awk将读入的每行,通过定界符(默认空格,可由-F指定),将该行分隔成每个段(域),利用 $1,$2,$3 ...表示第一段,第二段,第三段...;利用$0 表示整行。
Awk 程序更像是一种查询语言!
awk规则:
1,(指令),由模式+过程 组成,必须用单引号 ' ' 括起来。
2,(模式),即正则表达式,必须用斜杠 / /括起来。
3,(过程),即动作print等,必须用大括号 { } 括起来。
例子:list文件
John Daggett, 341 King Road, Plymouth MA
Alice Ford, 22 East Broadway, Richmond VA
Orville Thomas, 11345 Oak Bridge Road, Tulsa OK
Terry Kalkas, 402 Lans Road, Beaver Falls PA
Eric Adams, 20 Post Road, Sudbury MA
Hubert Sims, 328A Brook Road, Roanoke VA
Amy Wilde, 334 Bayshore Pkwy, Mountain View CA
Sal Carpenter, 73 6th Street, Boston MA
$ awk -F, '/MA/{print$1 ; print $2}' list //(像不像Mysql查询语言?)打印结果:
John Daggett
341 King Road
Eric Adams
20 Post Road
Sal Carpenter
73 6th Street
小问题2:用全名替换简写名,如California替换 CA
nameds.sed文件(注意,存储的是sed的命令集,而不是awk的指令集,从指令的形式上就可以看出来了)
s/ CA/, California/
s/ MA/, Massachusetts/
s/ OK/, Oklahoma/
s/ PA/, Pennsylvania/
s/ VA/, Virginia/
$ sed -f s.sed list1 //打印结果:
John Daggett, 341 King Road, Plymouth, Massachusetts
Alice Ford, 22 East Broadway, Richmond, Virginia
Orville Thomas, 11345 Oak Bridge Road, Tulsa, Oklahoma
Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
Eric Adams, 20 Post Road, Sudbury, Massachusetts
Hubert Sims, 328A Brook Road, Roanoke, Virginia
Amy Wilde, 334 Bayshore Pkwy, Mountain View, California
Sal Carpenter, 73 6th Street, Boston, Massachusetts
$ sed -f nameds.sed list | awk -F, '{print $4}' //sed结果通过 管道 做为awk的输入。打印结果:
Massachusetts
Virginia
Oklahoma
Pennsylvania
Massachusetts
Virginia
California
Massachusetts
$ sed -f names.sed list | awk -F, '{ print $4 ", " $0}' //打印结果:
Massachusetts, John Daggett, 341 King Road, Plymouth, Massachusetts
Virginia, Alice Ford, 22 East Broadway, Richmond, Virginia
Oklahoma, Orville Thomas, 11345 Oak Bridge Road, Tulsa, Oklahoma
Pennsylvania, Terry Kalkas, 402 Lans Road, Beaver Falls, Pennsylvania
Massachusetts, Eric Adams, 20 Post Road, Sudbury, Massachusetts
Virginia, Hubert Sims, 328A Brook Road, Roanoke, Virginia
California, Amy Wilde, 334 Bayshore Pkwy, Mountain View, California
Massachusetts, Sal Carpenter, 73 6th Street, Boston, Massachusetts
初级问题3:按州的名字排序并列出州的名字,以及所有住在那个州的人的姓名?
以问题2的结果作为管道的输入,
管道输出到awk.sh脚本文件:
#! /bin/sh
awk -F, '{ print $4 ", " $0 }' |sort | awk -F,
'$1==LastState { print "\t" $2 }
$1!=LastState {
LastState=$1
print $1
print "\t" $2
}'
这里注意四个小问题,1,chomd改awk.sh权限;2,./awk.sh执行;3,第一个awk的输入文件$* 可要可不要,为什么?4,在awk中,变量无需初始化,直接写上去即可使用,默认初始值整型为0,字符串型为空。
$ sed -f names.sed list1 | ./awk.sh //打印结果:
California
Amy Wilde
Massachusetts
Eric Adams
John Daggett
Sal Carpenter
Oklahoma
Orville Thomas
Pennsylvania
Terry Kalkas
Virginia
Alice Ford
Hubert Sims
小问题4:ipbaby项目上遇到过,以前觉得无从下手,现在a piece of cake !
H264_frame1.5Mps文件内容:
H264 NAL units(nalcount=3,nalsize=46941)
H264 NAL units(nalcount=1,nalsize=10014)
H264 NAL units(nalcount=1,nalsize=6360)
H264 NAL units(nalcount=1,nalsize=3245)
H264 NAL units(nalcount=1,nalsize=3746)
......
要求:提取nalsize后面的数字,单独放在一个文件中。(方便直接拷入excel作图)
结果重定向到datah264中,答案有很多,以下是其中两种:
$ sed 's/)//' ./H264_frame1.5Mps | awk -F= '{print $3}' > datah264
或者写个shell脚本:my.sh
#!/bin/sh
sed 's/)//' $* | awk -F= '{print $3}' > datah264
$ ./my.sh ./H264_frame1.5Mps
注意:my.sh脚本中的 $* 表示命令行中的 “./H264_frame1.5Mps”参数字符串。
小问题5:提取H264_frame1.5Mps文件中的括号内的内容?
按前面的思路,用sed将 ‘)’ 消除,然后awk在以 ‘(‘ 分隔:
$ sed '/)//' h264_frame1.5mps | awk -F( '{print $2}'
bash: syntax error near unexpected token `('
出错!
不认识’(’,好吧,由于我知识有限,目前为快速达到目标,绕过它就是了:
$ sed -e 's/)//' -e 's/(/,/' h264_frame1.5mps | awk -F, '{print $2"," $3}'
输出:
nalcount=3,nalsize=46941
nalcount=1,nalsize=10014
nalcount=1,nalsize=6360
nalcount=1,nalsize=3245
nalcount=1,nalsize=3746
如果我知道转义能使’)’成为awk的分隔符,那么为什么不这样?
$ awk -F[\(\)] '{print $2}' h264_frame1.5mps
输出:同样结果
其中[]内同时指定了两个分隔符,’(’和’)’,提取$2就可以了!
这样,对于小问题4,有更简单的方法:
$ awk -F[\(\)=] '{print $4}' h264_frame1.5mps
输出:
46941
10014
6360
3245
3746
Awk小结:
$ awk [ -Fre] [-f progfile] ['prog'] [parameter...] [in_file]
参数说明:
-Fre:允许awk更改其字段分隔符。(其中re的格式为"pattern" )
-F[\(\)=] 等价于 -F"[\(\)=]" 等价于 -F"\(|\)|="
-f progfile:允许awk调用并执行progfile指定有程序文件。progfile是一个文本文件,他必须符合awk的语法。(jsf,存储awk的指令/pattern/ {action} )
'prog': awk的程序语句段。这个语句段必须用单拓号:'和'括起,以防被shell解释。这个程序语句段的标准形式为:
'/pattern/ {action}'
其中参数pattern可以是egrep正则表达式中的任何一个,它可以使用语法/re/再加上一些样式匹配技巧构成。与sed类似,你也可以使用","分开两样式以选择某个范围。关于匹配的细节,你可以参考附录,如果仍不懂的话,找本UNIX书学学grep和sed(本人是在学习ed时掌握匹配技术的)。参数action总是被大括号包围,它由一系列awk语句组成,各语句之间用";"(或回车)分隔。awk解释它们,并在pattern给定的样式匹配的记录上执行其action操作。与shell类似,你也可以使用“#”作为注释符,它使“#”到行尾的内容成为注释,在解释执行时,它们将被忽略。你可以省略pattern和action之一,但不能两者同时省略,当省略pattern时没有样式匹配,表示对所有行(记录)均执行action操作,省略action时执行缺省的操作——在标准输出上显示。
parameter: 该参数帮助为不同的变量赋值。格式 var=value,注意等号两边不能有空格,除非空格是var或value的一部分。$ awk -f progfile n=1 test1 n=2 test2 参数同输入文件test12一样,会在BEGIN执行以后再解析。处理过程是:以输入文件分隔,先单独处理完 n=1 test1两个输入(如同没有n=2 test2 参数一样),处理完成后,(如同没有n=1 test1参数样)再处理 n=2 test2。问题是,对两个输入文件,BEGIN会执行两次吗?测试是仅执行一次。
如果想要在shell可执行程序或命令行中传递的参数再BEGIN 执行前解析,可以使用-v选线,例如$ awk -v var=9 -f progfile n=1 test1 n=2 test2 var在BEGIN之前解析。
in_file:awk的输入文件,awk允许对多个输入文件进行处理。值得注意的是awk不修改输入文件。如果未指定输入文件,awk将接受标准输入,并将结果显示在标准输出上,awk支持输入输出重定向。
jsf,通过未指定输入文件,可以快速实时测试/pattern/模式的正确性与否,
例如如下语句:
$ awk -F"\n" '$1 ~ /^d.*:$/ {print "ok"}'
#其中的 ~ 符号,表示输入的整行 $1与 /pattern/ 匹配,若成功,则打印 “ok”