字符串屏蔽序列
1. 字符转换
2. 格式化输出
3.向一行a w k命令传值
4. awk脚本文件
5. 在awk中使用FS变量
6. 向awk脚本传值
=================================
字符串屏蔽序列
使用字符串或正则表达式时,有时需要在输出中加入一新行或查询一元字符。
打印一新行时,(新行为字符 n),给出其屏蔽序列,以不失其特殊含义,用法为在字符串前加入反斜线。例如使用 n强迫打印一新行。
如果使用正则表达式,查询花括号( { }),在字符前加反斜线,如/ { /,将在a w k中失掉其特殊含义。
代码: |
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。
代码: |
[root@chenwy sam]# awk 'BEGIN {print"
May Day
May 104141171"}'
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修饰符
代码: |
- 左对齐 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不做换行动作。
代码: |
A[sam@chenwy sam]$ echo "65" | awk '{printf "%c
",$0}' A |
按同样方式使用a w k得到同样结果。
代码: |
[sam@chenwy sam]$ awk 'BEGIN{printf "%c
",65}' A |
所有的字符转换都是一样的,下面的例子表示进行浮点数转换后‘ 9 9 9’的输出结果。整数传入后被加了六个小数点。
代码: |
[sam@chenwy sam]$ awk 'BEGIN{printf "%f
",999}' 999.000000 |
2. 格式化输出
打印所有的学生名字和序列号,要求名字左对齐, 1 5个字符长度,后跟序列号。注意 n换行符放在最后一个指示符后面。输出将自动分成两列。
代码: |
[root@chenwy sam]# awk '{printf "%-15s %s
",$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。
代码: |
[root@chenwy sam]# awk 'BEGIN{print "Name S.Number"}{printf "%-15s %s
",$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变量,需要将变量放在命令行中,格式如下:
(后面会讲到怎样传递变量到a w k脚本中)。
下面的例子在命令行中设置变量A G E等于1 0,然后传入a w k中,查询年龄在1 0岁以下的所有学生。
代码: |
[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中指定
的值进行查询测试。
代码: |
[root@chenwy sam]# df -k|awk '{if($4/boot 458589 /dev/shm 99352 |
代码: |
[root@chenwy sam]# df -k|awk '($4~/^[0-9]/) {if($4/ 2610716 /boot 458589 /dev/shm 99352 |
($4~/^[0-9]/)好像没什么用
在系统中使用df -k命令,产生下列信息:
代码: |
[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命令第一列包含注册用户名,这里打印注册用户,并加入一定信息。
代码: |
[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中获得相应信息。
代码: |
[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程序。文本如下:
代码: |
[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} |
通过将命令分开,脚本可读性提高,还可以在命令之间加入注释。这里加入头
信息和结尾的平均值。基本上这是一个一行脚本文件。
执行时,在脚本文件后键入输入文件名,但是首先要对脚本文件加入可执行权限。
代码: |
[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中有多条重复错误提法:
代码: |
[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脚本如下:
代码: |
[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} |
执行结果如下:
代码: |
[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选项可以在命令行中指定域分隔符。
代码: | $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域是帐号所有者。 我举的例子是第七个域:
代码: | [sam@Linux_chenwy sam]$ awk -F: '{print $1," ",$7}' passwd root /bin/bash bin /sbin/nologin daemon /sbin/nologin adm /sbin/nologin lp /sbin/nologin sync /bin/sync ................................. |
这是不用脚本的,后面的结果省略
现使用脚本如下:
代码: | [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," ",$7} |
结果如下:
代码: | [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一行命令传值方式大体相同,格式为:
代码: | awk script_file var=value input_file |
下述脚本对比检查文件中域号和指定数字。这里使用了N F变量M A X,表示指定检查的域号,使用双引号将域分隔符括起来,即使它是一个空格。 脚本如下:
代码: | [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个域),运行上述脚本。参数格式如下:
代码: | [sam@Linux_chenwy sam]$ chmod u+x fieldcheck.awk [sam@Linux_chenwy sam]$ ./fieldcheck.awk MAX=7 FS=":" passwd |
正好7个域,如果改成6,就会显示不同结果,试试看?
使用前面一行脚本的例子,将之转换成a w k脚本如下:
代码: | [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} |
文本包括了比实际命令更多的信息,没关系,仔细研读文本后,就可以精确知道其功能及如何调用它。 不要忘了增加脚本的可执行权限,然后将变量和赋值放在命令行脚本名字后、输入文件前执行。
代码: | [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命令获得输入,并输出块和字节数。
代码: | [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=" "; print "name" " ","bytes","blocks
" print "==============================="} {print $2," ",$1*512,$1} |
使用du的结果如下
代码: | [root@Linux_chenwy sam]# du 12 ./.kde/Autostart 16 ./.kde 8 ./.xemacs 4 ./sam 4 ./dir1 4 ./file6 184 . |
执行:
代码: | [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 |
代码: | OFS=" "; 数组 前面讲述s p l i t函数时,提到怎样使用它将元素划分进一个数组。这里还有一个例子:
代码: | [sam@Linux_chenwy sam]$ awk 'BEGIN {print split("123#456#789",myarray,"#")}' 3 |
实际上m y a r r a y数组为
代码: | Myarray[1]="123" Myarray[2]="456" Myarray[3]="789" |
数组使用前,不必定义,也不必指定数组元素个数。经常使用循环来访问数组。下面是一种循环类型的基本结构:
代码: | For (element in array ) print array[element] |
对于记录“ 1 2 3 # 4 5 6 # 6 7 8”,先使用s p l i t函数划分它,再使用循环打印各数组元素。操作脚本如下:
代码: | [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作为输入文件。
代码: | 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函数使用数组。也可以预先定义数组,并使用它与域进行比较测试,下面的例子中将使用更多的数组。 下面是从空手道数据库卸载的一部分数据,包含了学生级别及是否是成人或未成年人的信息,有两个域,分隔符为( #),文件如下:
代码: | [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脚本,然后做进一步讲解。
代码: | [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"} |
运行脚本前记住要加入可执行权限
代码: | [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 |
|
|
阅读(789) | 评论(0) | 转发(0) |