移至原简书https://www.jianshu.com/p/2ee...最近有很多搜索和编辑文件的需求和分析日志,在我对sed和awk的一般用法有一个浅薄的了解之前,这些只是肤浅的。学习了这段时间,才知道sed和awk真的很强大。Awkawk更擅长分析文件和执行列操作。条件类型加动作连接到文件。这里把条件类型加上动作看成一个组,一个命令可以放多个组。花括号{}支持print、if、while、for、逻辑判断等格式。$awk'{pattern+action}'{filenames}fieldEdit例如,在第一列我们需要输出test.log:[root@localhost~]#awk'{print$1}'test.log192.29.7.26192.29.7.14192.26.2.26192.15.25.26awk是这样操作的,读取一条由'n'换行符分隔的记录,然后将记录按照指定的字段分隔符分成字段,填充字段。$0表示所有域,$1表示第一个域,$n表示第n个域。默认的字段分隔符是“空白”或“[制表符]”,所以$1表示第一列代表IP。使用-F指定分隔符,如:[root@localhost~]#awk-F'"''{print$1}'test.log192.29.7.26--[14/Dec/2015:20:58:18+0800]POST/praiseHTTP/1.1192.29.7.14--[14/Dec/2015:20:58:19+0800]GET/apiHTTP/1.1192.26.2.26--[14/Dec/2015:20:58:19+0800]GET/apiHTTP/1.1192.15.25.26--[14/Dec/2015:20:58:19+0800]GET/apiHTTP/1.1也可以指定打印分隔符,第一个和第四个列使用选项卡显示。[root@localhost~]#awk'{print$1"\t"$4}'test.log还有很多:[root@localhost~]#awk'/200/'text.log//在里面搜索200个字符thefileThelineof[root@localhost~]#awk'{printNR,NF,$1,$NF}'test.log//显示文件file的当前记录数,域数和首尾domainofeachline[root@localhost~]#awk'/string/{print"\047good\047"}{print$1,$2}'test.log//找到匹配的对象字符串,并输出其后的具体符号,/047代表引号[root@localhost~]#awk'BEGIN{OFS="%"}{print$1,$2}'test.log//改变日志格式输出%[root@localhost~]#awk-F':''BEGIN{print"name,shell"}{print$1","$7}END{print"blue,/bin/nosh"}'//输入前后可以加特定标识,经常用inscriptstomergeandsplitfilesSeries:[root@localhost~]awk'{print$0}'file1file2file3>file//saucefile1,file2,file3合并成fileawk不需要在变量前加$符号,与shell不同的是,上面例子中用到了一些变量,在awk中善于使用变量会大大增加工具的实用性。每个变量的含义如下。ARGC命令行参数编号ARGV命令行参数数组FILENAME当前输入文件名FNR当前文件中的记录数FS输入字段分隔符,默认为空格RS输入记录分隔符NF当前记录中的字段数NRsofar到目前为止的记录数OFS输出域分隔符ORS输出记录分隔符数组和自定义变量除了awk的内置变量外,awk还可以自定义变量。[root@localhost~]#awk'{count++;print$1;}END{printcount}'test.log192.29.7.26192.29.7.14192.26.2.26192.15.25.264比如刘先生说要看numberofrequestsperminute,每分钟的请求数可以这样列出:[root@localhost~]#awk-F:'{count[$2":"$3]++}END{for(minuteincount)printminute,count[minute]}'test.log20:584使用数组统计日志中的IP请求次数[root@localhost~]#awk'{a[$1]+=1;}END{for(iina){printa[i]""i;}}'test.log复合表达式可以使用&&或||连接多个表达式,表达式扩展为()(expr1)&&(expr2)(expr1)||(expr)例如需要查看日志中某个时刻被中断的请求数:awk'$4>="[01/Dec/2015:15:00:00"&&$4<="[01/Dec/2015:22:00:00"'test.logIF和C语言一样,基本格式是这样的if(expression1){action1}elseif(expression2){action2}else{action3}来个栗子?有如下文字,要求:第一列将重复的合并为一行,第二列用最长地址0001|hi0002|dog0001|It'sagoodday0003|cat0001|nice0004|linux的列填充,结果应该是:0001|今天天气不错0002|dog0003|cat0004|Linux代码:#!/bash/binBEGIN{FS=OFS="|";i=1;}{if(a[$1]==0){b[i]=$1;a[$1]=$2;i++}if(length(a[$1])}END{for(j=1;j}比较代码:(不完整的实现)awk'BEGIN{FS=OFS="|"}!(length(a[$1])>length($2)){a[$1]=$2}END{for(iina)printi,a[i]}'data.txt解释:本例中,两个数组,a用来和$1关联,b用来顺序记录,这样最后的打印完全按照$1的顺序。条件句首先判断数组元素是否是第一次写入,如果不是,则比较$2的当前值和之前的值。存储值长度。不完整的代码无法顺序打印。这段代码在$1重复时效果很好,$2的长度在第一次、第二次和第三次递减。但是,当每次获取的$2长度不确定时,代码无法实现上述功能。例如:如果本例中第5行第2列比第3行第2列长,则不完整的代码无法实现需求。
