Ubuntu Shell命令awk程序中使用
Ubuntu Shell 对于电脑使用的玩家的常用软件,然后我就学习及深入的研究Ubuntu Shell ,在这里和大家一起探讨Ubuntu Shell 的使用方法,希望对大家有用。
awk程序中使用 Ubuntu Shell 命令
awk程序中允许呼叫Ubuntu Shell指令. 并提供管道解决awk与系统间数据传递的问题. 所以awk很容易使用系统资源. 读者可利用这个特点来编写某些适用的系统工具.
写一个awk程序来打印出线上人数. 将下列程序建文件, 命名为 count.awk BEGIN { while ( "who" | getline ) n++ print n } 并执行下列命令 : awk -f count.awk 执行结果将会印出目前在线人数
awk 程序并不一定要处理数据文件. 以本例而言, 仅输入程序文件count.awk, 未输入任何数据文件. BEGIN 和 END 同为awk中的一种 Pattern. 以 BEGIN 为 Pattern的Actions ,只有在awk开始执行程序,尚未开启任何输入文件前, 被执行一次.(注意: 只被执行一次)
"|" 为 awk 中表示管道的符号. awk 把 | 之前的字符串"who"当成Ubuntu Shell上的命令, 并将该命令送往Ubuntu Shell执行, 执行的结果(原先应于屏幕印出者)则藉由pipe送进awk程序中. getline为awk所提供的输入指令.
其语法如下 : 语法由何处读取数据数据读入后置于getline var < file所指定的 file变量 var(var省略时,表示置于$0)getline varpipe 变量变量 var(var省略时,表示置于$0)
getline var见 注一 变量 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便可解决.
awk 程序的应用实例
本节将示范一个统计上班到达时间及迟到次数的程序. 这程序每日被执行时将读入二个文件: 员工当日到班时间的数据文件 ( 如下列之 arr.dat ) 存放员工当月迟到累计次数的文件. 当程序执行执完毕后将更新第二个文件的数据(迟到次数), 并打印当日的报表.这程序将分成下列数小节逐步完成, 其大纲如下:
在到班资料文件 arr.dat 之前增加一行抬头 "ID Number Arrvial Time", 并产生报表输出到文件today_rpt1 中.< 思考: 在awk中如何将数据输出到文件 > 将 today_rpt1 上的数据按员工代号排序, 并加注执行当日日期; 产生文件 today_rpt2 <思考 awk中如何运用系统资源及awk中Pipe之特性 >
将awk程序包含在一个Ubuntu Shell script文件中于 today_rpt2 每日报表上, 迟到者之前加上"*", 并加注当日平均到班时间;产生文件 today_rpt3 从文件中读取当月迟到次数, 并根据当日出勤状况更新迟到累计数. <思考 使用者在awk中如何读取文件数据 >
重定向输出到文件
awk中并未提供如 C 语言中之fopen() 指令, 也未有fprintf() 文件输出这样的指令. 但awk中任何输出函数之后皆可借助使用与UNIX 中类似的 I/O 重定向符, 将输出的数据重定向到指定的文件; 其符号仍为 > (输出到一个新产生的文件) 或 >> ( 添加输出的数据到文件末尾 ).
[例 :]在到班数据文件 arr.dat 之前增加一行抬头如下: "ID Number Arrival Time", 并产生报表输出到文件 today_rpt1中 建立如下文件并取名为reformat1.awk BEGIN { print " ID Number Arrival Time" > "today_rpt1" print "===========================" > "today_rpt1" } { printf(" %s %s"n", $1,$2 ) > "today_rpt1" }
执行: $awk -f reformat1.awk arr.dat 执行后将产生文件 today_rpt1, 其内容如下 : ID Number Arrival Time 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重定向符号应使用 " >>" (append)而非 " >". 本程序中若使用 ">" 将数据重导到 today_rpt1, awk 第一次执行该指令时会产生一个新档 today_rpt1, 其后再执行该指令时则把数据追加到today_rpt1文件末, 并非每执行一次就重开一个新文件.
若采用">>"其差异仅在第一次执行该指令时, 若已存在today_rpt1则 awk 将直接把数据append在原文件之末尾. 这一点, 与UNIX中的用法不同.
awk 中如何利用系统资源
awk程序中很容易使用系统资源. 这包括在程序中途调用 Ubuntu Shell 命令来处理程序中的部分数据; 或在调用 Ubuntu Shell 命令后将其产生的结果交回 awk 程序(不需将结果暂存于某个文件). 这一过程是借助 awk 所提供的管道 (虽然有些类似 Unix 中的管道, 但特性有些不同),及一个从 awk 中呼叫 Unix 的 Ubuntu Shell 命令的语法来达成的.
承上题, 将数据按员工ID排序后再输出到文件 today_rpt2 , 并于表头附加执行时的日期. awk 提供与 UNIX 用法近似的 pipe, 其记号亦为 "|". 其用法及含意如下 : awk程序中可接受下列两种语法:
[a. 语法] awk output 指令 | "Ubuntu Shell 接受的命令" ( 如 : print $1,$2 | "sort -k 1" ) [b. 语法] "Ubuntu Shell 接受的命令" | awk input 指令 ( 如 : "ls " | getline)
注 : awk input 指令只有 getline 一个. awk output 指令有 print, printf() 二个. 在a 语法中, awk所输出的数据将转送往 Ubuntu Shell , 由 Ubuntu Shell 的命令进行处理.以上例而言, print 所输出的数据将经由 Ubuntu Shell 命令 "sort -k 1" 排序后再送往屏幕(stdout).
上列awk程序中, "print$1, $2" 可能反复执行很多次, 其输出的结果将先暂存于 pipe 中,等到该程序结束时, 才会一并进行 "sort -k 1". 须注意二点 : 不论 print $1, $2 被执行几次, "sort -k 1" 的执行时间是 "awk程序结束时",
"sort -k 1" 的执行次数是 "一次". 在 b 语法中, awk将先调用 Ubuntu Shell 命令. 其执行结果将通过 pipe 送入awk程序,以上例而言, awk先让 Ubuntu Shell 执行 "ls",Ubuntu Shell 执行后将结果存于 pipe, awk指令 getline再从 pipe 中读取数据.
使用本语法时应留心: 以上例而言,awk "立刻"调用 Ubuntu Shell 来执行 "ls", 执行次数是一次. getline 则可能执行多次(若pipe中存在多行数据). 除上列 a, b 二中语法外, awk程序中其它地方如出现像 "date", "cls", "ls"... 这样的字符串, awk只把它当成一般字符串处理.
建立如下文件并取名为 reformat2.awk # 程序 reformat2.awk # 这程序用以练习awk中的pipe BEGIN { "date" | getline # Ubuntu Shell 执行 "date". getline 取得结果并以$0记录 print " Today is " , $2, $3 >"today_rpt2" print "=========================" > "today_rpt2" print " ID Number Arrival Time" >"today_rpt2" close( "today_rpt2" ) } {printf( "%s %s"n", $1 ,$2 ) | "sort -k 1 >>today_rpt2"}
执行如下命令: awk -f reformat2.awk arr.dat 执行后, 系统会自动将 sort 后的数据追加( Append; 因为使用 " >>") 到文件 today_rpt2末端. today_rpt2 内容如下 : awk程序由三个主要部分构成 :
[ i.] Pattern { Action} 指令 [ ii.] 函数主体. 例如 : function double( x ){ return 2*x } (参考第11节 Recursive Program ) [ iii.] Comment ( 以 # 开头识别之 )
awk 的输入指令 getline, 每次读取一列数据. 若getline之后未接任何变量, 则所读入之资料将以$0 记录, 否则以所指定的变量储存之.
执行 "date" | getline 后, $0 之值为 "2007年 09月 21日 星期五 14:28:02 CST",当 $0 之值被更新时, awk将自动更新相关的内建变量, 如: $1,$2,..,NF.故 $2 之值将为"09月", $3之值将为"21日".
(有少数旧版的awk不允许即使用者自行更新(update)$0的值,或者更新$0时,它不会自动更新 $1,$2,..NF. 这情况下, 可改用gawk或nawk. 否则使用者也可自行以awk字符串函数split()来分隔$0上的数据)