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 VA 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
NRFILENAME

要快速 查看记录个数,应使用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 RN 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