Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7485011
  • 博文数量: 368
  • 博客积分: 9600
  • 博客等级: 上校
  • 技术积分: 18875
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-01 00:00
文章分类

全部博文(368)

文章存档

2017年(9)

2016年(19)

2015年(3)

2014年(6)

2013年(8)

2012年(78)

2011年(66)

2010年(135)

2009年(44)

分类: LINUX

2010-04-23 15:16:39

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 5a w kp 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 ($5 M.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 ($5 print $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 wO r a n g eR 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 wO r a n g eR 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 wO r a n g eR 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 rs 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

阅读(3606) | 评论(0) | 转发(3) |
给主人留下些什么吧!~~