Chinaunix首页 | 论坛 | 博客
  • 博客访问: 285429
  • 博文数量: 155
  • 博客积分: 1688
  • 博客等级: 上尉
  • 技术积分: 1560
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-17 08:06
文章分类
文章存档

2011年(16)

2009年(137)

2008年(2)

awk

分类: LINUX

2009-08-08 11:08:05

awk:倾向于处理一行中分成数个字段,默认是以空格或是[Tab]来分开

可以处理后续文件(文件必须格式化)也可以读取来自前一个命令的标准输出来读取数据。

命令格式:awk  [-F field-saparator] ‘条件类型1{动作1}  条件2{动作2} … …’ filename

field-saparator                   是分隔符,默认是以空格来作为域的分隔符

如果未设置- F选项,a w k假定空格为域分隔符,并保持这个设置直到发现一新行,但如果设置了- F选项,则a w k每次读一条记录或一行,并使用指定的分隔符分隔指定域

实际动作在大括号{ }内指明,条件在圆括号是指定。

awk是以为单位来处理数据,并以字段来划分每行数据来对应本应的域标识,a w k执行时,其浏览域标记为$ 1$ 2 . . . $ n,第一栏是$1,第二栏$2 … …$0代表整行的数据

注意在打印各个域时要用逗号(,)隔开,比如:awk ‘{print $1,$3}’ filename,这样打印出来的各个域之间是以一个空格来分隔,如果打印多个域时不加分隔符,那么打印的域的数据就连接在一起。

运行awk命令出现错误信息时可相应查找:

确保整个a w k命令用单引号括起来。

确保命令内所有引号成对出现。

确保用大括号括起动作语句,awk是通过大括号来解释语法,用圆括号括起条件语句。

语法错误会在相应的语法下边用”^”符号标示出来,并有相应的错误提示。

 

使用awk时要确认数据是否有连续性,awk的输入数据大多数是一个文件或者是通过管道把前一个命令的标准输出作为自己的标准输入。

如果一行中的数据没有连续性,那格式化出来的数据可能不是我们想要的结果

awk中常用的屏蔽序列

\n     新行

\r      回车键

\t      Tab

 

一、抽取域,打印单独的记录

Ex:通过last把登陆帐号和对应 IP列出来,逗号(,)是以一个空格来划分各个域,可以通过用[Tab]键来分开

#last | awk '{print $1 "\t" $3}'

root    192.168.0.88

reboot  boot          ------------误判

#awk -F: '{print $1,$3}' passwd

printf函数常用的几个修饰符用于格式化输出

% c A S C I I字符

% d           整数

% f 浮点数

% s 字符串

# awk -F: '{printf "%-10s %-10s\n",$1,$3}' passwd

 

二、保存awk的输出

#awk ‘{print $0}’ passwd>passwd.new

# awk -F: '{print $1"\t"$3}' passwd > passwd.awk           /*不会在屏幕上显示数据*/

# awk -F: '{print $1"\t"$3}' passwd |tee passwd.awk     /*保存数据的同时还显示在屏幕上*/

 

三、打印报头和尾部信息

使用B E G I N语句设置计数和打印头。B E G I N语句使用在任何文本浏览动作之前,之后

文本浏览动作依据输入文件开始执行。E N D语句用来在a w k完成文本浏览动作后打印输出文本总数和结尾状态标志。如果不特别指明模式, a w k总是匹配或打印行数。

在第一行打印数据格式,之后的数据和第一行的数据格式相对应

#awk -F: 'BEGIN{printf "%-10s %-10s","Name","UID""\n-------------------------------"}{printf "%-10s %-10s\n",$1,$3}' passwd

在最后一行打印信息的结束提示语句

#awk -F: 'BEGIN{printf "%-10s %-10s\n","Name","UID""\n-------------------------------"}{printf "%-10s %-10s\n",$1,$3}END{print "---THE-END---"}' passwd

 

四、awk中正则表达式及其操作

正则表达式的元字符,在awk语句中使用正则表达式时要用转义符(\)把元字符转义

\  ^  $  .  []  |  ()  *  +  ?  {}             /*前边七个是一定要转义,后边四个可以不转*/

#awk -F: '($5~/\$/){print $1"\t"$5}' passwd

 

awk的逻辑运算字符(条件)

1)匹配模式

~       匹配

!~     不匹配

 

# awk '/cdnunion/' passwd

# awk -F: '$1~/ cdnunion /' passwd          /*只匹配第一个域为cdnunion才打印*/

对文件passwd中的第七个字段匹配bash关健字的才打印

# awk -F: '{if($7~/bash/) print $1"\t"$7}' passwd

对文件passwd中的第七个字段匹配nologin关健字的才打印

#awk -F: '{if($7!~/nologin/) print $1"\t"$7}' passwd

对大小写匹配

#awk -F: '$1~/ [Cc]dnunion/' passwd

# awk -F: '{if($1~/[Cc]dnunion/) print $1"\t"$3}' passwd         /*匹配则打印第一、三列*/

或的关系匹配(|)

#awk -F: '$1~/(root| cdnunion)/' passwd

# awk -F: '{if($1~/(root|cdnunion)/) print $1"\t"$3}' passwd

匹配任意字符(.)

c开头,后边接着6个任意字符最后是以n结尾

#awk -F: '{if($1~/^c......n/) print $1"\t"$3}' passwd

 

2)比较的匹配模式

>      大于

<      小于

>=     大于或等于

<=     小于或等于

==     等于

!=     不等于

要匹配第三个域大于500的数据,并列出帐号和第三个域

#awk -F: '($3>500){print $1"\t"$3}' passwd

# awk -F: '{if($3>500) print$1"\t"$3}' passwd

# awk -F: '{if($3>500) printf "%-10s %-10d\n",$1,$3}' passwd

域值比较操作

有两种方式测试一数值域是否小于另一数值域。

1) B E G I N中给变量名赋值。

2) 在关系操作中使用实际数值。

通常在B E G I N部分赋值是很有益的,可以在a w k表达式进行改动时减少很多麻烦。使用关系操作必须用圆括号括起来。

# awk -F: '{if($3>500)print $0}' passwd             /*直接以数值来代入*/

#awk -F: 'BEGIN{CDN=500}{if($3>CDN) print $0}' passwd     /*BEGIN部分对CDN赋值*/

#awk -F: 'BEGIN{CDN=500;AGE=600}{if($3>CDN&&$3多个条件*/

向一行a w k命令传值

a w k执行前将值传入a w k变量,需要将变量放在命令行中,格式如下:

awk 命令变量=输入文件值

#awk -F: '{if($3>AGE&&$3

和在BEGIN时就给变量赋值是一样的

# awk -F: 'BEGIN{CDN=600;AGE=500}{if($3>AGE&&$3

 

 

精确匹配(==)

#awk -F: '$3==”501”{ print $1"\t"$3}' passwd                           /*会把第三个域匹配501字符的全列出来*/

# awk -F: '{if($3=="501") print $1"\t"$3}' passwd         /*只匹配第三个域为501字符的域*/

精确不匹配(!=)

#awk -F: '{if($3!="500") print $0}' passwd

域之间的比较

#awk -F: '{if($3>$4) print $1"\t"$3,$4}' passwd  

 

 

复合逻辑模式

&&   and : 语句两边必须同时匹配为真。

||    or:语句两边同时或其中一边匹配为真。

多个条件匹配

#awk -F: '($3>500)&&($3<600) {print $1"\t"$3}' passwd

第一个域是cdnunion字符串,并且第三个域是500

#awk -F: '{if($1=="cdnunion" && $3==500) print $1"\t"$3}' passwd

第三个域的值是501或者是502

#awk -F: '($3==501)||($3==502){print $1"\t"$3}' passwd

第一个域是cdnunion字符串,并且第三个域是500或者501

# awk -F: '{if($1=="cdnunion" && $3~/(501|502)/) print $1"\t"$3}' passwd

 

awk常用的几个内置变量:

NF    每一行($0)拥有的的字段总数(默认),如果$NF就会列出最后个字段的数据出来

NR    当前awk所处理的是第几行数据

FS     当前的分隔符,默认是空格键,$FS列出完整的一行数据

FILENAME  awk浏览的文件名,$FILENAME列出完整的一行数据

# awk -F: '{print $1 "\tlines:" NR "\tcolumes:"NF} END {print FILENAME"\n" NR "\n" FS}' passwd | tail

NF是表示各行的域的个数,默认是打印域的总数,前边加上前置”$”变量符时就只打印最后一个域的名称

#echo "/home/cdnunion/cdnunion/cdn.txt" | awk -F/ '{print NF}'           /*5个域名*/

#echo "/home/cdnunion/cdnunion/cdn.txt" | awk -F/ '{print $NF}'         /*第五个域名cdn.txt*/

 

算术操作符

+      

-         

*      

/       

%      模运算

^       幂运算

设置输入域到域变量名

可以要awk中默认设置的域名换成有意义的自定义域名,在进行模式匹配或关系操作时更容易理解,一般的变量名设置方式为n a m e = $ n,这里n a m e为调用的域变量名, n     实际域号。

在设置了域变量名是后边一定要加一个分号(;),分号的作用是分隔a w k命令

# awk -F: '{(user=$1)(uid=$3)}{print user,uid}' passwd

#awk -F: '{user=$1;uid=$3;if(uid>500&&uid<600) print user"\t"uid}' passwd 

 

 

修改数值域的取值

当在a w k中修改任何域时,要注意实际输入文件是不可修改的,修改的只是保存在缓存里的a w k复本

# awk -F: '{if($1=="cdnunion") $3=$3+8;print $1"\t"$3}' passwd   /*显示了修改的值的同时又显示整个文本的内容*/

# awk -F: '{if($1=="cdnunion") {$3=$3+8;print $1"\t"$3}}' passwd/*只显示修改后的记录*/

# awk -F: '($1~/cdnunion/){$3=$3+8;print $1"\t"$3}' passwd   

#awk -F: '($1=="cdnunion") {$3=$3+8;print $1"\t"$3}' passwd

 

修改文本域

修改文本域即对其重新赋值一个新的字符串,操作的同时字符串要使用双引号(“”),并用圆括号括起整个语法。

# awk -F: '{if($1=="cdnunion")($1="cdn");print $1}' passwd            /*显示所有*/

#awk -F: '{if($1=="cdnunion"){($1="cdn");print $1}}' passwd /*只显示修改的域*/

# awk -F: '($1=="cdnunion"){($1="cdn");print $1"\t"$3}' passwd 

 

创建新的输出域

如果第三个域小于第四个域,那么新建域八来求它们的差值

# awk -F: '{if($3<$4) {$8=$4-$3;print $1"\t"$3"\t"$4"\t"$8}}' passwd

# awk -F: '($3<$4){$8=$4-$3;print $1"\t"$8}' passwd

增加列值

在最后添加一列来对以上数据进行统计求和,同时显示所有数据

#tail passwd | awk -F: '{(tot1+=$3)(tot2+=$4)};{print $1"\t"$3"\t"$4}END{print "Total:""\t\t"tot1"\t"tot2}'

下边命令只显示最后一行的结果

# tail passwd | awk -F: '{(tot1+=$3)(tot2+=$4)}END{print "Total:""\t\t"tot1"\t"tot2}'

 

统计数据

有张产品的销售表:goods.txt

Name    1st     2nd     3th

goods1  125     173     208

goods2  204     185     233

goods3  356     288     253

 

计算每件产品的销售总额:

# awk 'NR==1{printf"%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"} NR>=2{total=$2+$3+$4;  printf "%10s %10d %10d %10d %10.2f\n",$1,$2,$3,$4,total}' goods.txt

对每个月的所有商品的销售做统计

#awk '{print $0}NR>=2{(tot1+=$2)(tot2+=$3)(tot3+=$4)}END{print "Total:""\t"tot1"\t"tot2"\t"tot3}' goods.txt

#awk '{print $0}' goods.txt |awk ' NR>=2(tot1+=$2)(tot2+=$3)(tot3+=$4);END{print "total:""\t"tot1"\t"tot2"\t"tot3}'

两者结合

#awk 'NR==1{printf"%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"} NR>=2{total=$2+$3+$4;  printf "%10s %10d %10d %10d %10.2f\n",$1,$2,$3,$4,total}NR>=2{(tot1+=$2)(tot2+=$3)(tot3+=$4)(tot4+=$5)}END{printf "%10s %10d %10d %10d %10.2f\n","Total:",tot1,tot2,tot3,tot4}' goods.txt

 

 

文件长度相加

统计当前目录下所有文件的大小,目录除外

# ls -l | awk '/^[^d]/ {print $1,$5} {tot+=$5} END {print "Total:""\t"tot" KB"}'

 

阅读(1931) | 评论(0) | 转发(0) |
0

上一篇:在redhat上安装net-snmp

下一篇:sed

给主人留下些什么吧!~~