Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1043147
  • 博文数量: 326
  • 博客积分: 10135
  • 博客等级: 上将
  • 技术积分: 2490
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-22 23:53
文章分类

全部博文(326)

文章存档

2014年(1)

2012年(4)

2011年(1)

2010年(4)

2009年(41)

2008年(44)

2007年(63)

2006年(168)

我的朋友

分类: LINUX

2007-01-12 14:04:25

下面没有讲述a w k的全部特性,也不涉及a w k的深层次编程,仅讲述使用a w k执行行操作及怎样从文本文件和字符串中抽取信息。

QUOTE:
内容有:
" 抽取域。
" 匹配正则表达式。
" 比较域。
" 向a w k传递参数。
" 基本的a w k行操作和脚本。
a w k语言的最基本功能是在文件或字符串中基于指定规则浏览和抽取信息。a w k抽取信息后,才能进行其他文本操作。完整的a w k脚本通常用来格式化文本文件中的信息。

1 调用awk

有三种方式调用a w k,第一种是命令行方式,如:

CODE:
awk [-F fild-separator] 'commands' input-file(s)
这里,c o m m a n d s是真正的a w k命令。
上面例子中, [ - F域分隔符]是可选的,因为a w k使用空格作为缺省的域分隔符,因此如果要浏览域间有空格的文本,不必指定这个选项,但如果要浏览诸如p a s s w d文件,此文件各域以冒号作为分隔符,则必须指明- F选项,如:

CODE:
awk -F:  'commands' input-file(s)
第二种方法是将所有a w k命令插入一个文件,并使a w k程序可执行,然后用a w k命令解释器作为脚本的首行,以便通过键入脚本名称来调用它。

第三种方式是将所有的a w k命令插入一个单独文件,然后调用:

CODE:
awk -f awk-script-file input-files(s)
- f选项指明在文件a w k _ s c r i p t _ f i l e中的a w k脚本, i n p u t _ f i l e ( s )是使用a w k进行浏览的文件名。

2 awk脚本
在命令中调用a w k时,a w k脚本由各种操作和模式组成。
如果设置了- F选项,则a w k每次读一条记录或一行,并使用指定的分隔符分隔指定域,但如果未设置- F选项,a w k假定空格为域分隔符,并保持这个设置直到发现一新行。当新行出现时,a w k命令获悉已读完整条记录,然后在下一个记录启动读命令,这个读进程将持续到文件尾或文件不再存在。

参照表,a w k每次在文件中读一行,找到域分隔符(这里是符号#),设置其为域n,直至一新行(这里是缺省记录分隔符),然后,划分这一行作为一条记录,接着a w k再次启动下一行读进程。
awk读文件记录的方式

QUOTE:
域1                         分隔符        域2                分隔符        域3        分隔符        域4及换行
P. B u n n y (记录1 )         #         0 2 / 9 9         #         4 8         #         Yellow \n
J . Tr o l l (记录2 )         #         0 7 / 9 9         #         4 8 4 2 #         Brown-3 \n
2.1 模式和动作
任何a w k语句都由模式和动作组成。在一个a w k脚本中可能有许多语句。模式部分决定动作语句何时触发及触发事件。处理即对数据进行的操作。如果省略模式部分,动作将时刻保持执行状态。
模式可以是任何条件语句或复合语句或正则表达式。模式包括两个特殊字段B E G I N和E N D。使用B E G I N语句设置计数和打印头。B E G I N语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文件开始执行。E N D语句用来在a w k完成文本浏览动作后打印输出文本总数和结尾状态标志。如果不特别指明模式, a w k总是匹配或打印行数。
实际动作在大括号{ }内指明。动作大多数用来打印,但是还有些更长的代码诸如i f和循环(l o o p i n g)语句及循环退出结构。如果不指明采取动作, a w k将打印出所有浏览出来的记录。
 
2. 域和记录
a w k执行时,其浏览域标记为$ 1,$ 2 . . . $ n。这种方法称为域标识。使用这些域标识将更容易对域进行进一步处理。
使用$ 1 , $ 3表示参照第1和第3域,注意这里用逗号做域分隔。如果希望打印一个有5个域的记录的所有域,不必指明$ 1 , $ 2 , $ 3 , $ 4 , $ 5,可使用$ 0,意即所有域。Aw k浏览时,到达一新行,即假定到达包含域的记录末尾,然后执行新记录下一行的读动作,并重新设置域分隔。
注意执行时不要混淆符号$和s h e l l提示符$,它们是不同的。
为打印一个域或所有域,使用p r i n t命令。这是一个a w k动作(动作语法用圆括号括起来)。


1. 抽取域
真正执行前看几个例子,现有一文本文件g r a d e . t x t,记录了一个称为柔道数据库的行信息。

CODE:
$ cat 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
L.Tansl 05/99   4712 Brown-2 12 30 28
此文本文件有7个域,即(1)名字、(2)升段日期、(3)学生序号、(4)腰带级别、(5)年龄、(6)目前比赛积分、(7)比赛最高分。
因为域间使用空格作为域分隔符,故不必用- F选项划分域,现浏览文件并导出一些数据。在例子中为了利于显示,将空格加宽使各域看得更清晰。

2. 保存a w k输出
有两种方式保存s h e l l提示符下a w k脚本的输出。最简单的方式是使用输出重定向符号>文件名,下面的例子重定向输出到文件w o w。

CODE:
$ awk '{print $0}' grade.txt >wow
$ cat grade.txt
使用这种方法要注意,显示屏上不会显示输出结果。因为它直接输出到文件。只有在保证输出结果正确时才会使用这种方法。它也会重写硬盘上同名数据。

第二种方法是使用t e e命令,在输出到文件的同时输出到屏幕。在测试输出结果正确与否时多使用这种方法。例如输出重定向到文件d e l e t e _ m e _ a n d _ d i e,同时输出到屏幕。使用这种方法,在a w k命令结尾写入| tee delete_me_and_die。

CODE:
$ awk '{print $0}' grade.txt | tee delete_me_and_die
3. 使用标准输入
在深入讲解这一章之前,先对a w k脚本的输入方法简要介绍一下。实际上任何脚本都是从标准输入中接受输入的。为运行本章脚本,使用a w k脚本输入文件格式,例如:

QUOTE:
belts.awk grade_student.txt
也可替代使用下述格式:
使用重定向方法:
belts.awk < grade2.txt
或管道方法:
grade2.txt | belts.awk
这里我怎么看不明白,汗

4. 打印所有记录

CODE:
$ awk '{print $0}' grade.txt
a w k读每一条记录。因为没有模式部分,只有动作部分{print $0}(打印所有记录),这个动作必须用花括号括起来。上述命令打印整个文件。

5. 打印单独记录
假定只打印学生名字和腰带级别,通过查看域所在列,可知为f i e l d - 1和f i e l d - 4,因此可以使用$ 1和$ 4,但不要忘了加逗号以分隔域。

CODE:
$ awk '{print $1,$4}' grade.txt
M.Tans Green
J.Lulu green
P.Bunny Yellow
J.Troll Brown-3
L.Tansl Brown-2
6. 打印报告头
上述命令输出在名字和腰带级别之间用一些空格使之更容易划分,也可以在域间使用t a b键加以划分。为加入t a b键,使用t a b键速记引用符\ t,后面将对速记引用加以详细讨论。也可以为输出文本加入信息头。本例中加入n a m e和b e l t及下划线。下划线使用\ n,强迫启动新行,并在\ n下一行启动打印文本操作。打印信息头放置在B E G I N模式部分,因为打印信息头被界定为一个动作,必须用大括号括起来。在a w k查看第一条记录前,信息头被打印。

CODE:
$ awk 'BEGIN {print "Name Belt\n-----------------------------------"}{print $1"\t",$4}' grade.txt
Name Belt
-----------------------------------
M.Tans   Green
J.Lulu   green
P.Bunny  Yellow
J.Troll  Brown-3
L.Tansl  Brown-2
7. 打印信息尾
如果在末行加入end of report信息,可使用E N D语句。E N D语句在所有文本处理动作执行完之后才被执行。E N D语句在脚本中的位置放置在主要动作之后。下面简单打印头信息并告之查询动作完成。

CODE:
$ awk 'BEGIN {print "Name\n--------"}{print $1} END {print "end-of-report"}' grade.txt
Name
--------
M.Tans
J.Lulu
P.Bunny
J.Troll
L.Tansl
8. awk错误信息提示
几乎可以肯定,在使用a w k时,将会在命令中碰到一些错误。a w k将试图打印错误行,但由于大部分命令都只在一行,因此帮助不大。
系统给出的显示错误信息提示可读性不好。使用上述例子,如果丢了一个双引号, a w k将返回:

CODE:
$ awk 'BEGIN {print "Name\n--------}{print $1} END {"end-of-report"}' grade.txt
awk: cmd. line:1: BEGIN {print "Name\n--------}{print $1} END {"end-of-report"}
awk: cmd. line:1:                                                            ^ unterminated string
当第一次使用a w k时,可能被错误信息搅得不知所措,但通过长时间和不断的学习,可总结出以下规则。在碰到a w k错误时,可相应查找:

QUOTE:
" 确保整个a w k命令用单引号括起来。
" 确保命令内所有引号成对出现。
" 确保用花括号括起动作语句,用圆括号括起条件语句。
" 可能忘记使用花括号,也许你认为没有必要,但a w k不这样认为,将按之解释语法

如果查询文件不存在,将得到下述错误信息:

CODE:
$ awk 'END {print NR}' grades.txt
awk: cmd. line:2: fatal: cannot open file `grades.txt' for reading (没有那个文件或目录)
9.awk 键盘输入
如果在命令行并没有输入文件g r a d e . t x t,将会怎样?

CODE:
$ awk 'BEGIN {print "Name\n--------"}{print $1} END {"end-of-report"}'
Name
--------
B E G I N部分打印了文件头,但a w k最终停止操作并等待,并没有返回s h e l l提示符。这是因为a w k期望获得键盘输入。因为没有给出输入文件, a w k假定下面将会给出。如果愿意,顺序输入相关文本,并在输入完成后敲键。如果敲入了正确的域分隔符, a w k会像第一个例子一样正常处理文本。这种处理并不常用,因为它大多应用于大量的打印稿。


2.3awk中正则表达式及其操作

在g r e p一章中,有许多例子用到正则表达式,这里将不使用同样的例子,但可以使用条件操作讲述a w k中正则表达式的用法。
这里正则表达式用斜线括起来。例如,在文本文件中查询字符串G r e e n,使用/ G r e e n /可以查出单词G r e e n的出现情况。

2.4元字符
这里是a w k中正则表达式匹配操作中经常用到的字符,详细情况请参阅本书第7章正则表达式概述。

CODE:
\ ^ $ . [] | () * + ?
这里有两个字符第7章没有讲到,因为它们只适用于a w k而不适用于g r e p或s e d。它们是:

QUOTE:
+ 使用+匹配一个或多个字符。
? 匹配模式出现频率。例如使用/X Y?Z/匹配X Y Z或Y Z。
字符串屏蔽序列

使用字符串或正则表达式时,有时需要在输出中加入一新行或查询一元字符。
打印一新行时,(新行为字符\ n),给出其屏蔽序列,以不失其特殊含义,用法为在字符串前加入反斜线。例如使用\ n强迫打印一新行。
如果使用正则表达式,查询花括号( { }),在字符前加反斜线,如/ \ { /,将在a w k中失掉其特殊含义。

CODE:
awk中使用的屏蔽序列
\ b 退格键
\ t t a b键
\ f 走纸换页
\ d d d 八进制值
\ n 新行
\ c 任意其他特殊字符,例如\ \为反斜线符号
\ r 回车键
使用上述符号,打印May Day,中间夹t a b键,后跟两个新行,再打印May Day,但这次使用八进制数1 0 4、1 4 1、1 7 1、分别代表D、a、y。

CODE:
[root@chenwy sam]# awk 'BEGIN {print"\n\May\tDay\n\nMay\t\104\141\171"}'

May     Day

May     Day
注意,\ 1 0 4为D的八进制A S C I I码,\ 1 4 1为a的八进制A S C I I码,等等。

awk输出函数printf
目前为止,所有例子的输出都是直接到屏幕,除了t a b键以外没有任何格式。a w k提供函数p r i n t f,拥有几种不同的格式化输出功能。例如按列输出、左对齐或右对齐方式。
每一种p r i n t f函数(格式控制字符)都以一个%符号开始,以一个决定转换的字符结束.转换包含三种修饰符。
p r i n t f函数基本语法是p r i n t f([格式控制符],参数),格式控制字符通常在引号里。

printf修饰符

CODE:
- 左对齐
Wi d t h 域的步长,用0表示0步长
. p r e c 最大字符串长度,或小数点右边的位数
表9-7 awk printf格式
% c A S C I I字符
% d 整数
% e 浮点数,科学记数法
% f 浮点数,例如(1 2 3 . 4 4)
% g a w k决定使用哪种浮点数转换e或者f
% o 八进制数
% s 字符串
% x 十六进制数
1. 字符转换
观察A S C I I码中6 5的等价值。管道输出6 5到a w k。p r i n t f进行A S C I I码字符转换。这里也加入换行,因为缺省情况下p r i n t f不做换行动作。

CODE:
A[sam@chenwy sam]$ echo "65" | awk '{printf "%c\n",$0}'
A
按同样方式使用a w k得到同样结果。

CODE:
[sam@chenwy sam]$ awk 'BEGIN{printf "%c\n",65}'
A
所有的字符转换都是一样的,下面的例子表示进行浮点数转换后‘ 9 9 9’的输出结果。整数传入后被加了六个小数点。

CODE:
[sam@chenwy sam]$ awk 'BEGIN{printf "%f\n",999}'
999.000000
2. 格式化输出
打印所有的学生名字和序列号,要求名字左对齐, 1 5个字符长度,后跟序列号。注意\ n换行符放在最后一个指示符后面。输出将自动分成两列。

CODE:
[root@chenwy sam]# awk '{printf "%-15s %s\n",$1,$3}' grade.txt
M.Tans          48311
J.Lulu          48317
P.Bunny         48
J.Troll         4842
L.Tansl         4712
加入一些文本注释帮助理解报文含义。可在正文前嵌入头信息。注意这里使用p r i n t加入头信息。如果愿意,也可使用p r i n t f。

CODE:
[root@chenwy sam]# awk 'BEGIN{print "Name\t\tS.Number"}{printf "%-15s %s\n",$1,$3}' grade.txt
Name            S.Number
M.Tans          48311
J.Lulu          48317
P.Bunny         48
J.Troll         4842
L.Tansl         4712
3.向一行a w k命令传值
在查看a w k脚本前,先来查看怎样在a w k命令行中传递变量。
在a w k执行前将值传入a w k变量,需要将变量放在命令行中,格式如下:

CODE:
awk 命令变量=输入文件值
(后面会讲到怎样传递变量到a w k脚本中)。
下面的例子在命令行中设置变量A G E等于1 0,然后传入a w k中,查询年龄在1 0岁以下的所有学生。

CODE:
[root@chenwy sam]# awk '{if ($5M.Tans 5/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
要快速查看文件系统空间容量,观察其是否达到一定水平,可使用下面a w k一行脚本。因为要监视的已使用空间容量不断在变化,可以在命令行指定一个触发值。首先用管道命令将df -k 传入a w k,然后抽出第4列,即剩余可利用空间容量。使用$ 4 ~ / ^ [ 0 - 9 ] /取得容量数值(1 0 2 4块)而不是d f的文件头,然后对命令行与‘ i f ( $ 4 < T R I G G E R )’上变量T R I G G E R中指定
的值进行查询测试。

CODE:
[root@chenwy sam]# df -k|awk '{if($4/boot   458589
/dev/shm        99352


CODE:
[root@chenwy sam]# df -k|awk '($4~/^[0-9]/) {if($4/       2610716
/boot   458589
/dev/shm        99352
($4~/^[0-9]/)好像没什么用

在系统中使用df -k命令,产生下列信息:

CODE:
[root@chenwy sam]# df -k
文件系统               1K-块        已用     可用 已用% 挂载点
/dev/sda2              5162828   2289804   2610764  47% /
/dev/sda1               497829     13538    458589   3% /boot
none                     99352         0     99352   0% /dev/shm
如果系统中d f输出格式不同,必须相应改变列号以适应工作系统。
当然可以使用管道将值传入a w k。本例使用w h o命令, w h o命令第一列包含注册用户名,这里打印注册用户,并加入一定信息。

CODE:
[sam@chenwy sam]$ who |awk '{print $1" is logged on"}'
root is logged on
root is logged on
[sam@chenwy sam]$ who
root     :0           Nov 23 20:17
root     pts/0        Nov 23 20:25 (:0.0)
a w k也允许传入环境变量。下面的例子使用环境变量HOME支持当前用户目录。可从pwd命令管道输出到a w k中获得相应信息。

CODE:
[sam@chenwy sam]$ pwd | awk '{if ($1==derr) print $1}' derr=$HOME
/usr/sam
4. awk脚本文件
可以将a w k脚本写入一个文件再执行它。命令不必很长(尽管这是写入一个脚本文件的主要原因),甚至可以接受一行命令。这样可以保存a w k命令,以使不必每次使用时都需要重新输入。使用文件的另一个好处是可以增加注释,以便于理解脚本的真正用途和功能。
使用前面的几个例子,将之转换成a w k可执行文件。像原来做的一样,将学生目前级别分相加awk ‘(t o t + = $ 6) END{print "club student total points:" t o t }’ g r a d e . t x t。
创建新文件s t u d e n t _ t o t . a w k,给所有a w k程序加入a w k扩展名是一种好习惯,这样通过查看文件名就知道这是一个a w k程序。文本如下:

CODE:
[sam@chenwy sam]$ cat student_tot.awk
#!/bin/awk -f
#all commnet lines must start with a hash '#'
#name:students_tots.awk
#to call:student_tot.awk grade.txt
#prints total and average of club student points

#print a header first
BEGIN{
print "Student  Date  Member  No.  Grade Age  Points Max"
print "Name     Joined                        Gained  Point Available"
print "=============================================================="
}
#let's add the scores of points gained
(tot+=$6)

#finished proessing now let's print the total and average point
END{
print "Club student total points :" tot
print "Average Club Student Points:" tot/NR}
通过将命令分开,脚本可读性提高,还可以在命令之间加入注释。这里加入头
信息和结尾的平均值。基本上这是一个一行脚本文件。
执行时,在脚本文件后键入输入文件名,但是首先要对脚本文件加入可执行权限。

CODE:
[sam@chenwy sam]$ chmod u+x student_tot.awk
[sam@chenwy sam]$./student_tot.awk grade.txt
Student  Date  Member  No.  Grade Age  Points Max
Name     Joined                        Gained  Point Available
==============================================================
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
L.Tansl 05/99 4712 Brown-2 12 30 28
Club student total points :155
Average Club Student Points:31
过滤相同行:
如有一个文件strip中有多条重复错误提法:

CODE:
[sam@Linux_chenwy sam]$ cat strip
etreiytrpytyu
ERROR*
ERROR*
ERROR*
ERROR*
IUEWROPYJRTMELUYK
ERROR*
ERROR*
ERROR*
ERROR*
ERROR*
ERROR*
EWUTIRWJYHT
ERROR*
ERROR*
JGIOERYO56ERU
ERROR*
ERROR*
ERROR*
JGEORYKP65EKU;YK,
现在用a w k脚本过滤出错误行的出现频率,使得每一个失败记录只对应一个错误行。awk脚本如下:

CODE:
[sam@Linux_chenwy sam]$ cat error_strip.awk
#!/bin/awk -f
#error_strip.awk
#to call:error_strip.awk
#strips out the ERROR* lines if there are more than one
#ERROR* lines after each failed record.

BEGIN {error_line=""}
#tell awk the whole is "ERROR*"
{if ($0=="ERROR*" && error_line=="ERROR*")

#go to next line
next;
error_line=$0;print}
执行结果如下:

CODE:
[sam@Linux_chenwy sam]$ ./error_strip.awk strip
etreiytrpytyu
ERROR*
IUEWROPYJRTMELUYK
ERROR*
EWUTIRWJYHT
ERROR*
JGIOERYO56ERU
ERROR*
JGEORYKP65EKU;YK,
5. 在a w k中使用F S变量
如果使用非空格符做域分隔符( F S)浏览文件,例如# 或:,编写这样的一行命令很容易,因为使用F S选项可以在命令行中指定域分隔符。

CODE:
$awk -F: '{print $0}' inputfile
使用a w k脚本时,记住设置F S变量是在B E G I N部分。如果不这样做, a w k将会发生混淆,不知道域分隔符是什么。
下述脚本指定F S变量。脚本从/ e t c / p a s s w d文件中抽取第1和第5域,通过分号“;”分隔p a s s w d文件域。第1域是帐号名,第5域是帐号所有者。
我举的例子是第七个域:

CODE:
[sam@Linux_chenwy sam]$ awk -F: '{print $1,"\t",$7}' passwd
root     /bin/bash
bin      /sbin/nologin
daemon   /sbin/nologin
adm      /sbin/nologin
lp       /sbin/nologin
sync     /bin/sync
.................................
这是不用脚本的,后面的结果省略

现使用脚本如下:

CODE:
[sam@Linux_chenwy sam]$ cat passwd.awk
#!/bin/awk -f
#to call:passwd.awk /etc/passwd
#print out the first and seventh fields
BEGIN{
FS=":"}
{print $1,"\t",$7}
结果如下:

CODE:
[sam@Linux_chenwy sam]$ chmod u+x passwd.awk
[sam@Linux_chenwy sam]$ ./passwd.awk passwd
root     /bin/bash
bin      /sbin/nologin
daemon   /sbin/nologin
adm      /sbin/nologin
lp       /sbin/nologin
sync     /bin/sync
.......................................
6. 向a w k脚本传值
向a w k脚本传值与向a w k一行命令传值方式大体相同,格式为:

CODE:
awk script_file var=value input_file
下述脚本对比检查文件中域号和指定数字。这里使用了N F变量M A X,表示指定检查的域号,使用双引号将域分隔符括起来,即使它是一个空格。
脚本如下:

CODE:
[sam@Linux_chenwy sam]$ cat fieldcheck.awk
#!/bin/awk -f
#check on how many fields in a file
#name:fieldcheck.awk
#to call:fieldcheck MAX=n FS= filename
#
NF!=MAX{
print("line" NR " does not have " MAX "fields")}
如果NF中的值不等于最大MAX值,则打印出"哪一行的域总数不是max"

如果以/ e t c / p a s s w d作输入文件(p a s s w d文件有7个域),运行上述脚本。参数格式如下:

CODE:
[sam@Linux_chenwy sam]$ chmod u+x fieldcheck.awk
[sam@Linux_chenwy sam]$ ./fieldcheck.awk MAX=7 FS=":" passwd
正好7个域,如果改成6,就会显示不同结果,试试看?

使用前面一行脚本的例子,将之转换成a w k脚本如下:

CODE:
[sam@Linux_chenwy sam]$ cat name.awk
#!/bin/awk -f
#name:age.awk
#to call:age.awk AGE=n grade.txt
#print ages that are lower than the age supplied on the comand line
{if ($5print $0}
文本包括了比实际命令更多的信息,没关系,仔细研读文本后,就可以精确知道其功能及如何调用它。
不要忘了增加脚本的可执行权限,然后将变量和赋值放在命令行脚本名字后、输入文件前执行。

CODE:
[sam@Linux_chenwy sam]$ chmod u+x name.awk
[sam@Linux_chenwy sam]$ ./name.awk AGE=10 grade.txt
M.Tans 5/99 48311 Green 8 40 44
J.Lulu 06/99 48317 green 9 24 26
同样可以使用前面提到的管道命令传值,下述a w k脚本从d u命令获得输入,并输出块和字节数。

CODE:
[root@Linux_chenwy sam]# cat duawk.awk
#!/bin/awk -f
#to call:du|duawk.awk
#prints file/direc's in bytes and blocks
BEGIN{
OFS="\t";
print "name" "\t\t","bytes","blocks\n"
print "==============================="}
{print $2,"\t\t",$1*512,$1}
使用du的结果如下

CODE:
[root@Linux_chenwy sam]# du
12      ./.kde/Autostart
16      ./.kde
8       ./.xemacs
4       ./sam
4       ./dir1
4       ./file6
184     .
执行:

CODE:
[root@Linux_chenwy sam]# du | ./duawk.awk
name                    bytes   blocks

===============================
./.kde/Autostart                                6144    12
./.kde                          8192    16
./.xemacs                               4096    8
./sam                           2048    4
./dir1                          2048    4
./file6                         2048    4
.                               94208   184


CODE:
OFS="\t";
数组
前面讲述s p l i t函数时,提到怎样使用它将元素划分进一个数组。这里还有一个例子:

CODE:
[sam@Linux_chenwy sam]$ awk 'BEGIN {print split("123#456#789",myarray,"#")}'
3
实际上m y a r r a y数组为

CODE:
Myarray[1]="123"
Myarray[2]="456"
Myarray[3]="789"
数组使用前,不必定义,也不必指定数组元素个数。经常使用循环来访问数组。下面是一种循环类型的基本结构:

CODE:
For (element in array ) print array[element]
对于记录“ 1 2 3 # 4 5 6 # 6 7 8”,先使用s p l i t函数划分它,再使用循环打印各数组元素。操作脚本如下:

CODE:
[sam@Linux_chenwy sam]$ cat arraytest.awk
#!/bin/awk -f
#name:arraytest.awk
#prints out an array
BEGIN{
record="123#456#789";
split(record,myarray,"#")}
END{for (i in myarray) {print myarray[i]}}
要运行脚本,使用/ d e v / n u l l作为输入文件。

CODE:
sam@Linux_chenwy sam]$chmod u+x arraytest.awk
[sam@Linux_chenwy sam]$ ./arraytest.awk /dev/null
123
456
789
[sam@Linux_chenwy sam]$
数组和记录
上面的例子讲述怎样通过s p l i t函数使用数组。也可以预先定义数组,并使用它与域进行比较测试,下面的例子中将使用更多的数组。
下面是从空手道数据库卸载的一部分数据,包含了学生级别及是否是成人或未成年人的信息,有两个域,分隔符为( #),文件如下:

CODE:
[sam@Linux_chenwy sam]$ cat grade_student.txt
Yellow#Junior
Orange#Senior
Yellor#Junior
Purple#Junior
Brown-2#Junior
White#Senior
Orange#Senior
Red#Junior
Red#Junior
Brown-2#Senior
Yellow#Senior
Red#Junior
Blue#Senior
Green#Senior
Purple#Junior
White#Junior
脚本功能是读文件并输出下列信息。
1) 俱乐部中Ye l l o w、O r a n g e和R e d级别的人各是多少。
2 ) 俱乐部中有多少成年人和未成年人。
查看文件,也许2 0秒内就会猜出答案,但是如果记录超过6 0个又怎么办呢?这不会很容易就看出来,必须使用a w k脚本。
首先看看a w k脚本,然后做进一步讲解。

CODE:
[sam@Linux_chenwy sam]$ cat belts.awk
#!/bin/awk -f
#name:belts.awk
#to call:belts.awk grade2.txt
#loops through the grade2.txt file and counts how many
#belts we have in (yellow,orange,red)
#also count how many adults and juniors we have
#
#start of BEGIN
#set FS and load the arrays with our values

#B E G I N部分设置F S为符号#,即域分隔符

BEGIN{FS="#"

#Load the belt colours we are interested in only
#因为要查找Ye l l o w、O r a n g e和R e d三个级别。
#然后在脚本中手工建立数组下标对学生做同样的操作。
#注意,脚本到此只有下标或元素,并没有给数组名本身加任何注释。

belt["Yellow"]
belt["Orange"]
belt["Red"]
#end of BEGIN
#load the student type
student["Junior"]
student["Senior"]
}

##初始化完成后, B E G I N部分结束。记住B E G I N部分并没有文件处理操作。

#loop thru array that holds the belt colours against field-1
#if we have a match,keep a running total

#现在可以处理文件了。
#首先给数组命名为c o l o r,使用循环语句测试域1级别列是否
#等于数组元素之一(Ye l l o w、O r a n g e或R e d),
#如果匹配,依照匹配元素将运行总数保存进数组。

{for (colour in belt)
{if($1==colour)
belt[colour]++}}

#loop thru array that holds the student type against
#field-2 if we have a match,keep a runing total

#同样处理数组‘ S e n i o r _ o r _ j u n i o r’,
#浏览域2时匹配操作满足,运行总数存入j u n i o r或s e n i o r的匹配数组元素。

{for (senior_or_junior in student)
{if ($2==senior_or_junior)
student[senior_or_junior]++}}

#finished processing so print out the matches..for each array

#E N D部分打印浏览结果,对每一个数组使用循环语句并打印它。

END{for (colour in belt )print "The club has ",belt[colour],colour,"Belts"

#注意在打印语句末尾有一个\符号,用来通知a w k(或相关脚本)命令持续到下一行,
#当输入一个很长的命令,并且想分行输入时可使用这种方法。

for (senior_or_junior in student) print "The club has ",\
student[senior_or_junior],senior_or_junior,"student"}
运行脚本前记住要加入可执行权限

CODE:
[sam@Linux_chenwy sam]$ chmod u+x belts.awk
[sam@Linux_chenwy sam]$ ./belts.awk grade_student.txt
The club has  3 Red Belts
The club has  2 Orange Belts
The club has  2 Yellow Belts
The club has  7 Senior student
The club has  9 Junior student
阅读(1361) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~