当前位置:首页 > awk 命令详解教程
执行下列命令 :
$awk -f course.awk reg.dat
执行结果如下 :
Graphics 2 O.S. 2 Discrete 3 A.I. 1 D.S. 1 Arch. 2 Algorithm 2
[ 说 明 : ]
这程序包含二个Pattern { Actions }指令.
{ for( i=2; i <= NF; i++) Number[$i]++ }
END{for(course in Number) printf(\
第一个Pattern { Actions }指令中省略了Pattern 部分. 故随着 每笔数据行的读入其Actions部分将逐次无条件被执行.
以awk读入第一笔资料 \为例, 因为该笔数据 NF = 4(有4个字段), 故该 Action 的for Loop中i = 2,3,4. i $i 最初 Number[$i] Number[$i]++ 之后
i=2时 $i=\的值从默认的0,变成了1 ; i=3时 $i=\的值从默认的0,变成了1 ;
同理,i=4时 $i=\的值从默认的0,变成了1 ;
第二个 Pattern { Actions }指令中END 为awk之保留字, 为 Pattern 的一种. END 成立(其值为true)的条件是: \处理完所有数据, 即将离开程序时. \平常读入数据行时, END并不成立, 故其后的Actions 并不被执行;
唯有当awk读完所有数据时, 该Actions才会被执行 ( 注意, 不管数据行有多少笔, END仅在最后才成立, 故该Actions仅被执行一次.)
BEGIN 与 END 有点类似, 是awk中另一个保留的Pattern.
唯一不同的是: \以 BEGIN 为 Pattern 的 Actions 于程序一开始执行时, 被执行一次.\
NF 为awk的内建变量, 用以表示awk正处理的数据行中, 所包含的字段个数.
awk程序中若含有以 $ 开头的自定变量, 都将以如下方式解释 :
以 i= 2 为例, $i = $2 表第二个字段数据. ( 实际上, $ 在 awk 中为一运算符(Operator), 用以取得字段数据.)
6. awk 程序中使用 Shell 命令
awk程序中允许呼叫Shell指令. 并提供管道解决awk与系统间数据传递的问题. 所以awk很容易使用系统资源. 读者可利用这个特点来编写某些适用的系统工具.
[ 范例 : ] 写一个awk程序来打印出线上人数. 将下列程序建文件, 命名为 count.awk
BEGIN {
while ( \ print n }
并执行下列命令 :
awk -f count.awk
执行结果将会印出目前在线人数 [ 说 明 : ]
awk 程序并不一定要处理数据文件. 以本例而言, 仅输入程序文件count.awk, 未输入任何数据文件.
BEGIN 和 END 同为awk中的一种 Pattern. 以 BEGIN 为 Pattern的Actions ,只有在awk开始执行程序,尚未开启任何输入文件前, 被执行一次.(注意: 只被执行一次)
\为 awk 中表示管道的符号. awk 把 | 之前的字符串\当成Shell上的命令, 并将该命令送往Shell执行, 执行的结果(原先应于屏幕印出者)则藉由pipe送进awk程序中.
getline为awk所提供的输入指令. 其语法如下 : 语法 getline var < file getline var getline var 由何处读取数据 数据读入后置于 所指定的 file pipe 变量 见 注一 变量 var(var省略时,表示置于$0) 变量 var(var省略时,表示置于$0) 变量 var(var省略时,表示置于$0) 注一 : 当 Pattern 为 BEGIN 或 END 时, getline 将由 stdin 读取数据, 否则由awk正处理的数据文件上读取数据.
getline 一次读取一行数据, 若读取成功则return 1, 若读取失败则return -1, 若遇到文件结束(EOF), 则return 0;
本程序使用 getline 所 return 的数据来做为 while 判断循环停止的条件,某些awk版本较旧,并不容许使用者改变 $0 之值. 这种版的 awk 执行本程序时会产生 Error, 读者可于 getline 之后置上一个变量 (如此, getline 读进来的数据便不会被置于 $0 ), 或直接改用gawk便可解决.
7. awk 程序的应用实例
本节将示范一个统计上班到达时间及迟到次数的程序. 这程序每日被执行时将读入二个文件:
员工当日到班时间的数据文件 ( 如下列之 arr.dat ) 存放员工当月迟到累计次数的文件.
当程序执行执完毕后将更新第二个文件的数据(迟到次数), 并打印当日的报表.这程序将分成下列数小节逐步完成, 其大纲如下:
[7.1] 在到班资料文件 arr.dat 之前增加一行抬头
\并产生报表输出到文件today_rpt1 中. < 思考: 在awk中如何将数据输出到文件 >
[7.2]将 today_rpt1 上的数据按员工代号排序, 并加注执行当日日期; 产生文件 today_rpt2
<思考 awk中如何运用系统资源及awk中Pipe之特性 > [7.3] 将awk程序包含在一个shell script文件中
[7.4] 于 today_rpt2 每日报表上, 迟到者之前加上\并加注当日平均到班时间;
产生文件 today_rpt3
[7.5] 从文件中读取当月迟到次数, 并根据当日出勤状况更新迟到累计数. <思考 使用者在awk中如何读取文件数据 >
某公司其员工到勤时间档如下, 取名为 arr.dat. 文件中第一栏为员工代号, 第二栏为到达时间. 本范例中, 将使用该文件为数据文件.
1034 7:26 1025 7:27 1101 7:32 1006 7:45 1012 7:46 1028 7:49 1051 7:51 1029 7:57 1042 7:59 1008 8:01 1052 8:05 1005 8:12
?重定向输出到文件
awk中并未提供如 C 语言中之fopen() 指令, 也未有fprintf() 文件输出这样的指令. 但awk中任何输出函数之后皆可借助使用与UNIX 中类似的 I/O 重定向符, 将输出的数据重定向到指定的文件; 其符号仍为 > (输出到一个新产生的文件) 或 >> ( 添加输出的数据到文件末尾 ).
[例 :]在到班数据文件 arr.dat 之前增加一行抬头如下:
\并产生报表输出到文件 today_rpt1中 建立如下文件并取名为reformat1.awk
BEGIN { print \ print \ }
{ printf(\
执行:
$awk -f reformat1.awk arr.dat
执行后将产生文件 today_rpt1, 其内容如下 :
ID Number Arrival Time
============================ 1034 7:26 1025 7:27 1101 7:32 1006 7:45 1012 7:46 1028 7:49 1051 7:51 1029 7:57 1042 7:59 1008 8:01 1052 8:05 1005 8:12
[ 说 明 : ]
awk程序中, 文件名称 today_rpt1 的前后须以\双引号)括住, 表示 today_rpt1 为一字符串常量. 若未以\括住, 则 today_rpt1 将被awk解释为一个变量名称. 在awk中任何变量使用之前, 并不须事先声明. 其初始值为空字符串(Null string) 或 0.因此程序中若未以 \将 today_rpt1 括住, 则 today_rpt1 将是一变量, 其值将是空字符串, 这会在执行时造成错误(Unix 无法帮您开启一个以空字符串为文件名的文件).
因此在编辑awk程序时, 须格外留心. 因为若敲错变量名称,awk在编译程序时会认为是一新的变量, 并不会察觉. 因此往往会造成运行时错误. BEGIN 为awk的保留字, 是 Pattern 的一种.
以 BEGIN 为 Pattern 的 Actions 于awk程序刚被执行尚未读取数据文件时被执行一次, 此后便不再被执行.
读者或许觉得本程序中的I/O重定向符号应使用 \而非 \ 本程序中若使用 \将数据重导到 today_rpt1, awk 第一次执行该指令时会产生一个新档 today_rpt1, 其后再执行该指令时则把数据追加到today_rpt1文件末, 并非每执行一次就重开一个新文件.
若采用\其差异仅在第一次执行该指令时, 若已存在today_rpt1则 awk 将直接把数据append在原文件之末尾. 这一点, 与UNIX中的用法不同.
?awk 中如何利用系统资源
awk程序中很容易使用系统资源. 这包括在程序中途调用 Shell 命令来处理程序中的部分数据; 或在调用 Shell 命令后将其产生的结果交回 awk 程序(不需将结果暂存于某个文件). 这一过程是借助 awk 所提供的管道 (虽然有些类似 Unix 中的管道, 但特性有些不同),及一个从 awk 中呼叫 Unix 的 Shell 命令的语法来达成的.
[例 :] 承上题, 将数据按员工ID排序后再输出到文件 today_rpt2 , 并于表头附加执行时的日期.
共分享92篇相关文档