awk内置变量
a w k有许多内置变量用来设置环境信息。这些变量可以被改变。表9 - 3显示了最常使用的一些变量,并给出 其基本含义。
QUOTE:
awk内置变量
A R G C 命令行参数个数
A R G V 命令行参数排列
E N V I R O N 支持队列中系统环境变量的使用
FILENAME a w k浏览的文件名
F N R 浏览文件的记录数
F S 设 置输入域分隔符,等价于命令行- F选项
N F 浏 览记录的域个数
N R 已 读的记录数
O F S 输出域分隔符
O R S 输出记录分隔符
R S 控 制记录分隔符
QUOTE:
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语法中。
[Copy to clipboard] [ - ]
CODE:
[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
[Copy to clipboard] [ - ]
CODE:
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,最后打印结果。
[Copy to clipboard] [ - ]
CODE:
[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并 显示其目录。这里需要指定域分隔符/。
[Copy to clipboard] [ - ]
CODE:
[root@chenwy sam]# echo $PWD | awk -F/ ' {print $NF}'
sam
另一个 例子是显示文件名。
[Copy to clipboard] [ - ]
CODE:
[root@chenwy sam]# echo "/usr/local/etc/rc.sybase" | awk -F/ '{print $NF}'
rc.sybase
如果不 指定域分割符,返回的如下:
[Copy to clipboard] [ - ]
CODE:
[root@chenwy sam]# echo $PWD | awk '{print $NF}'
/usr/sam
[root@chenwy sam]# echo "/usr/local/etc/rc.sybase" | awk '{print $NF}'
/usr/local/etc/rc.sybase
awk操作符
在a w k中使用操作符,基本表达式可以划分为数字型、字符串型、变量型、域及数组元素,前面已经讲过一些。下面列出其完整列表。
在表达 式中可以使用下述任何一种操作符。
QUOTE:
= += *= / = %= ^ = 赋 值操作符
? 条件表达操作符
|| && ! 并、与、非(上一节已讲到)
~!~ 匹 配操作符,包括匹配和不匹配
< <= == != >> 关系操作符
+ - * / % ^ 算术操作符
+ + -- 前缀和后缀
前面已 经讲到了其中几种操作,下面继续讲述未涉及的部分。
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的记录,并最终打印名称和级别。
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk '{name=$1;belts=$4;if(belts ~/Yellow/) print name" is belt "belts}' grade.txt
P.Bunny is belt Yellow
2. 域值比较操作
有两种 方式测试一数值域是否小于另一数值域。
1) 在B E G I N中给变量名赋值。
2) 在 关系操作中使用实际数值。
通常在B E G I N部分赋值是很有益的,可以在a w k表达式进行改动时减少很多麻烦。
使用关 系操作必须用圆括号括起来。
下面的 例子查询所有比赛中得分在2 7点以下的学生。
用引号 将数字引用起来是可选的,“2 7”、2 7产生同样的结果。
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk '{if ($6<$7) print $0}' grade.txt
M.Tans 5/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
第二个 例子中给数字赋以变量名B A S E L I N E和在B E G I N部分给变量赋值,两者意义相同。
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk 'BEGIN{BASELINE="27"} {if ($6<BASELINE) print $0}' grade.txt
J.Lulu 06/99 48317 green 9 24 26
J.Troll 07/99 4842 Brown-3 12 26 26
3. 修改数值域取值
当在a w k中修改任何域时,重要的一点是要记住实际输入文件是不可修改的,修改的只是保存在缓存里的a w k复本。a w k会在变量N R或N F变量中反映出修改痕迹。
为修改 数值域,简单的给域标识重赋新值,如: $ 1 = $ 1 + 5,会将域1数值加5,但要确保赋值域其子集为数值型。
修改M . Ta n s l e y的目前级别分域,使其数值从4 0减为3 9,使用赋值语句$ 6 = $ 6 - 1,当然在实施修改前首先要匹配域名。
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk '{if($1=="M.Tans") {$6=$6-1};print $1,$6,$7}' grade.txt
M.Tans 39 44
J.Lulu 24 26
P.Bunny 35 28
J.Troll 26 26
L.Tansl 30 28
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk '{if($1=="M.Tans") {$6=$6-1;print $1,$6,$7}}' grade.txt
M.Tans 39 44
4. 修改文本域
修改文 本域即对其重新赋值。需要做的就是赋给一个新的字符串。在J . Tr o l l中加入字母,使其成为J . L . Tr o l l,表达式为$ 1 = " J . L . Tr o l l ",记住字符串要使用双秒号( " "), 并用圆括号括起整个语法。
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk '{if($1=="J.Troll") $1="J.L.Troll"; print $1}' grade.txt
M.Tans
J.Lulu
P.Bunny
J.L.Troll
L.Tansl
5. 只显示修改记录
上述例 子均是对一个小文件的域进行修改,因此打印出所有记录查看修改部分不成问题,但如果文件很大,记录甚至超过1 0 0,打印所有记录只为查看修改部分显然不合情理。在模式后面使用花括号将只打印修改部分。取得模式,再根据模式结果实施操 作,可能有些抽象,现举一例,只打印修改部分。注意花括号的位置。
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk '{if($1=="J.Troll") {$1="J.L.Troll"; print $1}}' grade.txt
J.L.Troll
不 知道为什么,我这里多了一个空行?
6. 创建新的输出域
在a w k中处理数据时,基于各域进行计算时创建新域是一种好习惯。创建新域要通过其他域赋予新域标识符。如创建一个基于其他域的加 法新域{ $ 4 = $ 2 + $ 3 },这里假定记录包含3个域,则域4为新建域,保存域2和域3相加结果。
在文件g r a d e . t x t中创建新域8保存域目前级别分与域最高级别分的 减法值。表达式为‘{ $ 8 = $ 7 - $ 6 }’,语法首先测试域目前级别分小于域最高级别分。新域因此只打印其值大于零的学生名称及其新域值。在B E G I N部分加入t a b键以对齐报告头。
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk 'BEGIN{print "Name\tDifference"}{if($6<$7) {$8=$7-$6;print $1,$8}}' grade.txt
Name Difference
M.Tans 4
J.Lulu 2
当然可 以创建新域,并赋给其更有意义的变量名。例如:
[Copy to clipboard] [ - ]
CODE:
[sam@chenwy sam]$ awk 'BEGIN{print "Name\tDifference"}{if($6<$7) {diff=$7-$6;print $1,diff}}' grade.txt
Name Difference
M.Tans 4
J.Lulu 2