查看文章
 
Shell精解2(转)
2008-07-03 14:11

第5章 awk 实用程式:awk作为一种UNIX工具
1. awk 简介
awk 是用来操作数据和产生报表的一种编程语言。数据可能来自标准输入、一个或多个文档或是个进程的输出。awk 能够用在命令行里用于简单操作,或能够为了较大的应用而写到程式中。常见的awk命令有awk、nawk等。awk从第1行到最后一行逐行扫描文档(或输入),并执行选定的操作(封装在花括号里)。本文章任何的例子使用的文档未经说明都在chap05目录下。
2. awk的格式
awk程式由awk命令,封装在引号里(或在一个文档里)的程式指令,和输入文档组成。假如没有指定一个输入文档,则输入来自标准输入(stin)键盘。
employees文档中的内容:
$ cat employees
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
1〉从文档输入
$ awk '/Mary/' employees 解释:打印employees文档中含有Mary的行
$ awk '{print $1}' employees
Tom
Mary
Sally
Billy
解释:打印文档employees中的第一个域。域的分隔符是空格。
nawk '/Sally/{print $1,$2}' employees 解释:只有找到了Sally的行才打印第一个域和第二个域。
2〉管道输入
$ df -k|awk '$4>;1024000' 解释:报告剩余空间大于1024000k的盘。
3. 格式化输出
1〉print函数
$ date
2005年04月30日 星期六 19时29分25秒 CST
$ date|awk '{print "Date:" $1 "\nTime:" $3}'
Date:2005年04月30日
Time:19时34分24秒
注意,用date命令查看时间格式。不同的语言可能格式也不相同,因此awk也要随之而变。\n是转义序列,表示换行符。常见转义序列如下表:
\b 退格
\f 换页
\n 换行
\r 回车
\t 跳格
\047 八进制值47,一个单引号
\c C代表任意其他字符,例如\''
例子2:
$ nawk '/Sally/{print "\t\tHave a nice day, "$1,$2 "\!"}' employees
Have a nice day, Sally Chang!
解释:假如包含模式Sally,则print函数打印两个跳格,串Have a nice day,第一个域和第二个域,然后跟叹号。 OFMT变量:当打印数字时,假如使用print函数,想控制精度时,能够用OFMT变量。默认配置是“%.6g”,也就是打印精度到小数点后6位。下面的例子能够改变精度。
$ nawk 'BEGIN{OFMT="%.2f"; print 1.23456789,12E-2}'
1.23 0.12
2〉printf函数
printf函数提供了强大的格式化输出功能,假如对c比较熟悉,就不会感觉太陌生。
c 字符
s 串
d 十进制数
ld 长十进制数
u 无符号十进制数
lu 无符号长十进制数
x 十六进制数
lx 长十六进制数
o 八进制数
lo 长八进制数
e 以科学技术发记的符点数
f 浮点数
g 从e或f转换中选择一种占用空间最少的记符点数
- 左对齐修饰符
# 整数在用八进制显示前面有个0;整数在用十六进制显示时前面有个0x
+ 对于用d、e、f和g的转换,带一个数字符号+或-显示整数
0 显示的值用0补而不是用空格
假设x=’A’ y=15 z=2.3 $1=Bob Smith
%c 打印一个单ASCII字符
$ printf "The character is %c\n" $x
The character is A
%d 打印一个十进制数
$ printf "The boy is %d years old\n" $y
The boy is 15 years old
%e 打印用科学计数法记的一个数
$ printf "z is %e\n" $z
z is 2.300000e+00
%f 打印一个符点数
$ printf "z is %f\n" $z
z is 2.300000
%o 打印一个数的八进制值
$ printf "y is %o\n" $y
y is 17
%s 打印一个字符串
$ printf "The name of the culprit is %s\n" $1
The name of the culprit is Bob Smith
%x 打印一个数的十六进制值
$ printf "y is %x\n" $y
y is f
$ echo UNIX |awk '{printf "|%-15s|\n",$1}'
|UNIX |
解释:echo命令输出从管道中送给awk。格式说明符说明将会打印一个占15个空格,左对齐,封装在竖杠里而且有换行的串。
$ awk '{printf "The name is %-15s ID is %8d\n",$1,$3}' employees
The name is Tom ID is 4424
The name is Mary ID is 5346
The name is Sally ID is 1654
The name is Billy ID is 1683
4. 在一个文档里的awk命令
假如awk命令放在文档里,就使用-f选项和awk文档名结合使用。处理过程:把一条记录读到awk的缓存里而且对该记录测试并执行awk文档里的每个命令。在awk完成对第一条记录的操作后,删除该记录并把下一条记录读入缓存,依此类推。假如操作不受模式控制,则默认行为是打印整个记录。
例子:
$ cat employees
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
$ cat awkfile
/^Mary/{print "Hello Mary!"}
{print $1, $2, $3}
$ nawk -f awkfile employees
Tom Jones 4424
Hello Mary!
Mary Adams 5346
Sally Chang 1654
Billy Black 1683
5. 记录和域
1〉记录:awk不把输入数据看作一个无穷的字符串,而是把他看作一种格式或结构。默认情况下把每行叫做一个记录(record),并以一个换行符终止。输入和输出的记录分隔符默认是回车符,保存在内置awk变量ORS和RS中。ORS和RS能够改变,但是方式有限。
例子:
$ nawk '{print $0}' employees
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
解释:变量$0保存当前记录,这条命令相当于nawk '{print}' employees
例子:
$ awk '{print NR,$0}' employees
1 Tom Jones 4424 5/12/66 543354
2 Mary Adams 5346 11/4/63 28765
3 Sally Chang 1654 7/22/54 650000
4 Billy Black 1683 9/23/44 336500
解释:NR代表行号。
2〉域
类似表中的字段,是指记录中的一个词条。默认域分隔符是空白区域,也就是空格或制表符(TAB)。Awk中用NF来记录每条记录的域数量。
3〉域分隔符
输入域分隔符:awk的内置变量FS保存输入域分隔符的值。当时用FS的默认值时,awk用空格或制表符分隔域,删除前导空白区和制表符。FS能够改变,能够在BEGIN语句中改变,也能够在命令中改变。要想在命
令中改变需要用-F选项。
举例:
$ cat employees2
Tom Jones:4424:5/12/66:543354
Mary Adams:5346:11/4/63:28765
Sally Chang:1654:7/22/54:650000
Billy Black:1683:9/23/44:336500
$ awk '{print $1,$2}' employees2
Tom Jones:4424:5/12/66:543354
Mary Adams:5346:11/4/63:28765
Sally Chang:1654:7/22/54:650000
Billy Black:1683:9/23/44:336500
$ awk -F: '{print $1,$2}' employees2
Tom Jones 4424
Mary Adams 5346
Sally Chang 1654
Billy Black 1683
举例2:多个域分隔符。假如使用多个域分隔符,要将其封装在方括号里。
$ nawk -F'[ :\t]' '{print $1,$2,$3}' employees2
Tom Jones 4424
Mary Adams 5346
Sally Chang 1654
Billy Black 1683
解释:把空格、制表符、冒号当成输入域分隔符。 输出域分隔符:默认的输出域分隔符用逗号来分隔,被分隔的域之间打印一个空格,假如域之间没有逗号,则打印时各域将挤在一起。
6.模式和操作
awk 模式(patterns)控制awk将对一行输入作什么样的操作。一个模式包括1个正则表达式,一个产生正确或错误条件的表达式,或他们的组合。默认操作时打印模式中符合表达式条件的各行。当读入一个模式时,有一条隐含的if语句。假如if语句是隐含的,周围能够没有花括号。
例子:
$ awk '$3;=
大于等于 x>;=y
>; 大于 x>;y
~ 和正则表达式相匹配 x~/y/
!~ 不和正则表达式相匹配 x!~/y/
关系操作符举例:
$ cat employees
Tom Jones 4423 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
$ awk '$3==4423' employees
Tom Jones 4423 5/12/66 543354
$ nawk '$3 >;5000{print $1}' employees
Mary
$ nawk '$2 !~/Adam/' employees
Tom Jones 4423 5/12/66 543354
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
条件表达式:一个条件表达式用两个符号,问号和冒号来给表达式求值。和一个if/else语句相比更简介。
2.条件表达式
格式:
conditional expression1?expression2:expression3
他等同于{if(expression1)
expression2
else
expression3
}
条件表达式举例:
nawk '{max=($1>;$2)?$1:$2;print max}' employees 解释:假如第一个域大于第二个域,就把第一个域的内容赋给max,反之把第二个域的内容赋给max,然后打印max
3.计算
能够在模式里执行计算。awk以浮点方式执行任何的算术运算。
操作符
+ 加 x+y
- 减 x-y
* 乘 x*y
/ 除 x/y
% 求模 x%y
^ 幂运算 x^y
4.复合模式
复合模式 (compound patterns) 是把模式和逻辑操作符相结合的表达式,给一个表达式从左到右求值。
操作符
&& 逻辑和 a&&b
|| 逻辑或 a||b
! 逻辑非 !a
复合模式举例:
$ nawk '$3>;4000 && $3;4000 && $3; 打印那些第一个月捐款超过100的人的姓名
$ awk -F: '$3>;100 {print $1}' lab4.data
2>; 打印那些第一个月捐款少于$60的人的姓名和电话号码
$ awk -F: '$3; 打印那些第三个月捐款在90到150之间的人
$ awk -F: '$5>;=90 && $5; 打印那些三个月捐款在800以上的人
$ awk -F: '$3+$4+$5>;800 {print $0}' lab4.data
5>; 打印那些平均每月捐款大于$150的人名和点话号码
$ nawk -F'[ :\t]' '($5+$6+$7)/3>;150{print $1,$3,$4}' lab4.data
6>; 打印那些区号不是916的人名 $ nawk -F'[ :\t]' '$3 !~/916/{print $1}' lab4.data
7>; 打印每条记录,记录号在前面 $ awk '{print NR,$0}' lab4.data
8>; 打印每个人的名字和捐款总额 $ nawk -F'[ :\t]' 'sum=($5+$6+$7) {print $1,sum}' lab4.data
第7章 awk实用程式:awk编程
1.变量
.. 数值和串常数
数值常数能够表示成整数、浮点、科学计数等。含有空格的串要封装在双引号里。例如"Hello world"。假如一个域或这数组元素为空,则串值为空。一个空行也被当作空串。
.. 用户自定义变量
用户自定义变量包括字母、数字和下划线,且不能以数字开头。在awk中变量不用声明,awk通过表达式的上下文推断变量类型,并且假如需要,还能够在不同类型的变量中相互转换。
. 递加和递减操作符(++和--)
和c++语言中相同。x++是后递加,++x是先递加。
.. 内置变量。
内值变量要大写,他们能够用在表达式里而且能够被重置。如下表
变量名
ARGC 命令行变元个数
ARGV 命令行变元组数
FILENAME 当前输入文档名
FNR 当前文档里的记录号
FS 输入域分隔符,默认是空格
NF 当前域里的域个数
NR 到现在为止的记录数
OFMT 数值输出格式
OFS 输出域分隔符
ORS 输出记录分隔符
RLENGTH 由match函数匹配的串的长度
RS 输入记录分隔符
RSTART 由match函数匹配的串偏移量
SUBSEP 下标分隔符
表7.2 nawk内置变量
内置变量举例:
$ nawk -F: '$1=="Mary Adams"{print NR,$1,$2,$NF}' employees2
2 Mary Adams 5346 28765
解释:-F选项把分隔符改成冒号。假如域1等于Mary Adams,则打印记录号、第一个域、第二个域和最后一个域($NF)
.. BEGIN模式
BEGIN模式后面跟一个操作模块,在awk处理文档之前执行该模块。BEGIN模式主要用来配置OFS、RS、FS等内置变量的值。
$ awk 'BEGIN{FS=":";OFS="\t";ORS="\n\n"}{print $1,$2,$3}' employees2
Tom Jones 4423 5/12/66
Mary Adams 5346 11/4/63
Sally Chang 1654 7/22/54
Mary Black 1683 9/23/44
解释:在处理输入文档之前,把域分隔符置成一个冒号,输出域分隔符制成跳格符,并把输出记录分隔符(ORS)配置成两个换行符。
.. END模式
END模式不和任何输入行相匹配,但是执行任何和END模式相关的操作。在任何行处理完毕之后再来处理END模式。
$ awk '/Mary/{count++}END{print "Mary was found " count " times."}' employees
Mary was found 1 times.
解释:对于包含Mary的每一行,count变量值都递增1。awk 处理完毕之后,END模块打印结果。
2.重定向和管道
.. 输出重定向:当把输出从awk重定向到一个UNIX文档时,使用shell重定向操作符。假如重定向操作符用在awk命令里面则必须将重定向文件用双引号括起来。例如:
$ awk '$4>;70 {print $1,$2 >;"passing_film"}' datafile
.. 输入重定向(getline)
getline 函数用来从标准输入,例如管道或文档来读入数据,而不是从正被处理的当前文档。getline 取得输入的下一行,并更新NF、NR和FNR等内置变量的值。假如getline找到记录则返回1,达到EOF(文
件结束)则返回0。假如有错误则返回-1。
.. 举例1:
$ nawk 'BEGIN{"date"|getline d;print d}' datafile
2005年05月06日 星期五 15时05分41秒 CST
解释:执行date命令,然后把输出从管道送到getline,并赋给自定义变量d,然后打印d。
.. 举例2:
$ nawk 'BEGIN{while("ls"|getline) print}'
awk.sc2
datafile
datafile2
employees
employees2
lab5.data
names
passwd
解释:将把ls的输出送到getline。对于每次循环,getline都从ls读取一个以上输出,然后打印到屏幕上
.. 举例3:
$ nawk 'BEGIN{printf "What is your name?";\
>; getline name; $1 ~ name {print "Found " name " on line ",NR "."}\
>; END{print "See ya, " name "."}' employees
What is your name?Wangzhonghai
See ya, Wangzhonghai.
解释:将在屏幕上打印What is your name?,并且等待用户响应。getline 函数将从终端(/dev/tty)接受输入,一直到输入一个换行符为止,然后把输入存到用户自定义变量name中。假如递一个域和name的值相匹配,则执行print函数。在END模式中打印”See ya,”然后跟name的值。
.. 举例4
$ nawk 'BEGIN{while (getline;0)lc++;print lc}'
16
解释:awk将从“/etc/passwd”读取各行,lc递增,直到EOF,然后打印lc的值。
3.管道
假如在一个awk程式中打开一个管道,则必须在打开另一个之前先关闭他。在管道符号由变的命令封装在双引号里。一次只能打开一个管道。下面的例子是将names文档中的姓名按照姓作为第一关键字,名作为第二关键字来进行倒排序:
$ awk '{print $1,$2|"sort -r +1 -2 +0 -1 "}' names
tony tram
john smith
dan savage
barbara nguyen
elizabeth lone
john goldenrod
susan goldberg
george goldberg
eliza goldberg
alice cheba
4.关闭文档和管道
假如在awk中再次使用一个文档或管道来读取或写入,则需要首先关闭管道。打开和关闭管道的例子能够参考/chap07/awk.sc3文档。(书中源代码没有这个文档,而书上错误很多。)
6.条件语句
1) if 语句
以if结构开头的语句是操作语句。在条件模式(conditional patterns)里,if是隐含的;在一个条件操作语句中,if要显式说明,并且后面跟一个封装在括弧里的表达式。假如跟在条件表达式后面的语句不止一条,
则语句组必须放在花括号里,并且用分号或换行符来分开。
格式:
if (expression){statement;statement;…}
举例1: $ nawk '{if($8>;15) print $1 " To high"}' datafile
举例2: $ nawk '{if($8>;15 && $8;NF。读取下一条的记录的时候i被重新初始化。
2) for循环 使用规则和c中相同。
举例:
$ nawk '{ for (i=1;i; print i,name}' employees
0 Jones
1 Adams
2 Chang
3 Black
解释:在数组name里的下标是个用户自定义变量x。++显示了一个值型的上下文。
.. 特别for循环
在for循环无效的情况下,即当串被用作下标或下标不是连续的数时,用特别for循环来读取一个关联数组。特别for循环把下标当作一个键来找到他的相关的值。
格式:
{for(item in arrayname){
print arrayname[item]}}
举例:
$ nawk '/^Tom/{name[NR]=$1};\
>; END{for(i in name){print name}}' db        ::::::不同的内核有不同的写法,不要硬套
Tom
Tom
Tommy
Tom
解释:这两个例子用NR(行号)来做下标,因此匹配Tom的模式的行不连续,数组下标不连续。假如用传统for来循环打印会在数组没有值的地方打印空值。通过使用特别for循环,只打印数组中有值的内容。

C shell
Bounne shell
Korn shell
变量 给局域变量赋值
set x=5
s=5
s=5
赋变量属性 typeset 给环境变量赋值
setenv NAME Bob
NAME=Bob
export NAME=Bob
存取变量
echo $NAME
set var=net
echo ${var}work
network
echo $NAME
var=net
echo ${var}work
network
echo $NAME或print
$NAME
var=net
print ${var}work
network
专用变量
该进程的PID $$
退出状态 $status $?
上一个后台作业 $!
数组 给数组赋值
Set x=(a b c)
Y[0]=a;y[1]=b;y[2]=c
Set –A fruit apples pears plums


类别:shell教程集||添加到搜藏 |分享到i贴吧|浏览(186)|评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
     

   
帮助中心 | 空间客服 | 投诉中心 | 空间协议
©2012 Baidu