awk执行行操作及怎样从文本文件和字符串中抽取信..
时间:2005-07-05 来源:sunyone
awk条件操作符
awk内置变量
awk操作符
内置的字符串函数
==========================================================
awk条件操作符
操作符描述
< 小于
> = 大于等于
< = 小于等于
== 等于
!= 不等于
~ 匹配正则表达式
!~ 不匹配正则表达式
1. 匹配
为使一域号匹配正则表达式,使用符号'~'后紧跟正则表达式,也可以用if语句。awk中if后面的条件用()括起来。
观察文件grade.txt,如果只要显示brown腰带级别可知其所在域为field-4,这样可以写出表达式{if($4~/Brown/) print}意即如果field-4包含brown,打印它。如果条件满足,则打印匹配记录行。可以编写下面脚本,因为这是一个动作,必须用花括号{}括起来。
代码: |
[root@Linux_chenwy sam]# awk '{if($4~/Brown/) print }' grade.txt J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 |
匹配记录找到时,如果不特别声明,awk缺省打印整条记录。使用if语句开始有点难,但不要着急,因为有许多方法可以跳过它,并仍保持同样结果。下面例子意即如果记录包含模式brown,就打印它:
代码: |
[root@Linux_chenwy sam]# awk '$4~/Brown/' grade.txt J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 |
2. 精确匹配
假定要使字符串精确匹配,比如说查看学生序号48,文件中有许多学生序号包含48,如果在field-3中查询序号48,awk将返回所有序号带48的记录:
代码: |
[root@Linux_chenwy sam]# awk '{if($3~/48/) print}' grade.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 4842 Brown-3 12 26 26 |
为精确匹配48,使用等号==,并用单引号括起条件。例如$3=="48"
代码: |
[root@Linux_chenwy sam]# awk '$3=="48"' grade.txt P.Bunny 02/99 48 Yellow 12 35 28 [root@Linux_chenwy sam]# awk '{if($3=="48") print}' grade.txt P.Bunny 02/99 48 Yellow 12 35 28 |
3. 不匹配
有时要浏览信息并抽取不匹配操作的记录,与~相反的符号是!~,意即不匹配。像原来使用查询brown腰带级别的匹配操作一样,现在看看不匹配情况。表达式!~/Brown/,意即查询不包含模式brown腰带级别的记录并打印它。
注意,缺省情况下,awk将打印所有匹配记录,因此这里不必加入动作部分。
代码: |
[root@Linux_chenwy sam]# awk '$4!~/Brown/' grade.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28 |
可以只对field-4进行不匹配操作,方法如下:
代码: |
[root@Linux_chenwy sam]# awk '{if($4!~/Brown/) print }' grade.txt J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 |
如果只使用命令awk $4!="brown"{print } grade.txt,将返回错误结果,因为用引号括起了brown,将只匹配‘brown而不匹配brown-2和brown-3,当然,如果想要查询非brown-2的腰带级别,可做如下操作:
代码: |
[root@Linux_chenwy sam]# awk '$4!="Brown-2" {print }' grade.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 4842 Brown-3 12 26 26 |
4. 小于
看看哪些学生可以获得升段机会。测试这一点即判断目前级别分field-6是否小于最高分field-7,在输出结果中,加入这一改动很容易。
代码: |
[root@Linux_chenwy sam]# awk '{if($6<$7) print }' grade.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 |
5. 小于等于
对比小于,小于等于只在操作符上做些小改动,满足此条件的记录也包括上面例子中的输出情况。
代码: |
[root@Linux_chenwy sam]# awk '{if($6 <= $7) print $1}' grade.txt M.Tans J.Lulu J.Troll |
6. 大于
代码: |
[root@Linux_chenwy sam]# awk '{if($6 > $7) print $1}' grade.txt P.Bunny L.Tansl |
7. 设置大小写
为查询大小写信息,可使用[ ]符号。在测试正则表达式时提到可匹配[ ]内任意字符或单词,因此若查询文件中级别为green的所有记录,不论其大小写,表达式应为'/[Gg]reen/'
代码: |
[root@Linux_chenwy sam]# awk '/[Gg]reen/' grade.txt M.Tans 5/99 48311 Green 8 40 44 J.Lulu 06/99 48317 green 9 24 26 |
8. 任意字符
抽取名字,其记录第一域的第四个字符是a,使用句点.。表达式/^...a/意为行首前三个字符任意,第四个是a,尖角符号代表行首。
代码: |
[root@Linux_chenwy sam]# awk '$1 ~ /^...a/' grade.txt M.Tans 5/99 48311 Green 8 40 44 L.Tansl 05/99 4712 Brown-2 12 30 28 |
9. 或关系匹配
为抽取级别为yellow或brown的记录,使用竖线符|。意为匹配|两边模式之一。注意,使用竖线符时,语句必须用圆括号括起来。
代码: |
[root@Linux_chenwy sam]# awk '$0 ~/(Yellow|Brown)/' grade.txt P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 |
上面例子输出所有级别为Ye l l o w或B r o w n的记录。
使用这种方法在查询级别为G r e e n或g r e e n时,可以得到与使用[ ]表达式相同的结果。
代码: |
[root@Linux_chenwy sam]# awk '/^M/' grade.txt M.Tans 5/99 48311 Green 8 40 44 |
10. 行首
不必总是使用域号。如果查询文本文件行首包含M的代码,可简单使用下面^符号:
代码: |
[root@Linux_chenwy sam]# awk '/^M/' grade.txt |
复合表达式即为模式间通过使用下述各表达式互相结合起来的表达式:
引用: |
&& AND : 语句两边必须同时匹配为真。 || O R:语句两边同时或其中一边匹配为真。 ! 非求逆 |
11. AND
打印记录,使其名字为‘P.Bunny且级别为Yellow,使用表达式($1=="P.Bunny" && $4=="Yellow" ),意为&&两边匹配均为真。完整命令如下:
代码: |
[root@Linux_chenwy sam]# awk '{if ($1=="P.Bunny" && $4=="Yellow") print $0}' grade.txt P.Bunny 02/99 48 Yellow 12 35 28 |
12. Or
如果查询级别为Yellow或Brown,使用或命令。意为"||"符号两边的匹配模式之一或全部为真。
代码: |
[root@Linux_chenwy sam]# awk '{if ($4=="Yellow" || $4~/Brown/) print $0}' grade.txt P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 |
原来不一定得加print,下面我自己对例一二做了一下
代码: |
1 [root@Linux_chenwy sam]# awk '$4~/Brown/' grade.txt J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 |
代码: |
2 [root@Linux_chenwy sam]# awk '$3=="48"' grade.txt P.Bunny 02/99 48 Yellow 12 35 28 |
代码: |
[root@Linux_chenwy sam]# awk '$3="48"' grade.txt M.Tans 5/99 48 Green 8 40 44 J.Lulu 06/99 48 green 9 24 26 P.Bunny 02/99 48 Yellow 12 35 28 J.Troll 07/99 48 Brown-3 12 26 26 L.Tansl 05/99 48 Brown-2 12 30 28 |
2中,我把=和==写错了,呵呵,一个是赋值,一个是等于
awk内置变量
awk有许多内置变量用来设置环境信息。这些变量可以被改变。表9-3显示了最常使用的一些变量,并给出其基本含义。
引用: |
awk内置变量 ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk浏览的文件名 FNR 浏览文件的记录数 FS 设置输入域分隔符,等价于命令行- F选项 NF 浏览记录的域个数 NR 已读的记录数 OFS 输出域分隔符 ORS 输出记录分隔符 RS 控制记录分隔符 |
引用: |
A R G C支持命令行中传入a w k脚本的参数个数。A R G V是A R G C的参数排列数组,其中每一元素表示为A R G V [ n ],n为期望访问的命令行参数。 E N V I R O N 支持系统设置的环境变量,要访问单独变量,使用实际变量名,例如E N V I R O N [“E D I TO R”] =“Vi”。 F I L E N A M E支持a w k脚本实际操作的输入文件。因为a w k可以同时处理许多文件,因此如果访问了这个变量,将告之系统目前正在浏览的实际文件。 F N R支持a w k目前操作的记录数。其变量值小于等于N R。如果脚本正在访问许多文件,每一新输入文件都将重新设置此变量。 F S用来在a w k中设置域分隔符,与命令行中- F选项功能相同。缺省情况下为空格。如果用逗号来作域分隔符,设置F S = ","。 N F支持记录域个数,在记录被读之后再设置。 O F S允许指定输出域分隔符,缺省为空格。如果想设置为#,写入O F S = " # "。 O R S为输出记录分隔符,缺省为新行( n)。 R S是记录分隔符,缺省为新行( n )。 |
NF、NR和FILENAME
要快速查看记录个数,应使用N R。比如说导出一个数据库文件后,如果想快速浏览记录个数,以便对比于其初始状态,查出导出过程中出现的错误。使用N R将打印输入文件的记录个数。print NR放在E N D语法中。
代码: |
[root@chenwy sam]# awk 'END{print NR}' grade.txt 5 |
如:所有学生记录被打印,并带有其记录号。使用N F变量显示每一条读记录中有多少个域,并在E N D部分打印输入文件名。
[root@chenwy sam]# awk '{print NF,NR,$0} END{print FILENAME}' grade.txt
代码: |
7 1 M.Tans 5/99 48311 Green 8 40 44 7 2 J.Lulu 06/99 48317 green 9 24 26 7 3 P.Bunny 02/99 48 Yellow 12 35 28 7 4 J.Troll 07/99 4842 Brown-3 12 26 26 7 5 L.Tansl 05/99 4712 Brown-2 12 30 28 grade.txt |
在从文件中抽取信息时,最好首先检查文件中是否有记录。下面的例子只有在文件中至少有一个记录时才查询B r o w n级别记录。使用A N D复合语句实现这一功能。意即至少存在一个记录后,查询字符串B r o w n,最后打印结果。
代码: |
[root@chenwy sam]# awk '{if (NR>0 && $4~/Brown/)print $0}' grade.txt J.Troll 07/99 4842 Brown-3 12 26 26 L.Tansl 05/99 4712 Brown-2 12 30 28 |
N F的一个强大功能是将变量$ P W D的返回值传入a w k并显示其目录。这里需要指定域分隔符/。
代码: |
[root@chenwy sam]# echo $PWD | awk -F/ ' {print $NF}' sam |
另一个例子是显示文件名。
代码: |
[root@chenwy sam]# echo "/usr/local/etc/rc.sybase" | awk -F/ '{print $NF}' rc.sybase |
如果不指定域分割符,返回的如下:
代码: | ||||||||
[root@chenwy sam]# echo $PWD | awk '{print $NF}'
awk操作符
前面已经讲到了其中几种操作,下面继续讲述未涉及的部分。 1. 设置输入域到域变量名 在a w k中,设置有意义的域名是一种好习惯,在进行模式匹配或关系操作时更容易理解。 一般的变量名设置方式为n a m e = $ n,这里n a m e为调用的域变量名, n为实际域号。例如设置学生域名为n a m e,级别域名为b e l t,操作为n a m e = $ 1 ; b e l t s = $ 4。注意分号的使用,它分隔a w k命令。下面例子中,重新赋值学生名域为n a m e,级别域为b e l t s。查询级别为Ye l l o w的记录,并最终打印名称和级别。
2. 域值比较操作 有两种方式测试一数值域是否小于另一数值域。 1) 在B E G I N中给变量名赋值。 2) 在关系操作中使用实际数值。 通常在B E G I N部分赋值是很有益的,可以在a w k表达式进行改动时减少很多麻烦。 使用关系操作必须用圆括号括起来。 下面的例子查询所有比赛中得分在2 7点以下的学生。 用引号将数字引用起来是可选的,“2 7”、2 7产生同样的结果。
第二个例子中给数字赋以变量名B A S E L I N E和在B E G I N部分给变量赋值,两者意义相同。
|