Chinaunix首页 | 论坛 | 博客
  • 博客访问: 139826
  • 博文数量: 17
  • 博客积分: 330
  • 博客等级: 一等列兵
  • 技术积分: 135
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-03 14:32
文章分类

全部博文(17)

文章存档

2015年(1)

2013年(2)

2012年(14)

分类: LINUX

2012-05-11 18:30:20

awk学习

awk 'script' files
其中script是如下形式:/pattern/{actions}
例如:awk '{print ;}'  files
大括号中的内容以(;)结尾,给awk定义了命令在何处结束

awk中最有用的功能是它自动将输入分成字段,一个字段是一个字符集合,
被一个或多个字段分隔符分隔开来。默认的字段分隔符是制表符和空格。
当一行被读入时,awk把它已经解析的字段放进第一个字段的变量1中,然后
是第二个变量2,以此类推。此处的变量1,用  $1  表示。
但awk中使用的$与shell中使用不同。

awk '{print $1, $3}' fruit_prices
更美观的一种打印方式为:
awk '{printf "%-15s, %s\n",$1, $3;}' fruit_prices
说明:$1与$3的顺序是可以颠倒的

执行指定模式操作

fruit_prices文件内容如下

Fruit     Price/lbs Quantity
Banana $0.89 100
Paech $0.79 65
Kiwi         $1.50 22
Pineapple         $1.29 35
Apple $89.99 78


按指定条件打印
#!/bin/sh
# $0 表示一整行,awk可以同时执行多个正则表达式
#只需要用单引号将其包在一起即可。
awk '
/\$[1-9]*\.[0-9][0-9]/ { print $0 , "*"; }
/\$0\.[0-9][0-9]/ { print $0 ; }
' fruit_prices

#end

执行如上代码,可以打印单价大于1的物价行后加一个*
然而如果按书上的代码:
awk '
/*\$[1-9][0-9]*\.[0-9][0-9]/ { print $0, "*"; }
/* \$0\.[0-9][0-9]*/ { print $0 ; }
' fruit_prices
则无法正常打印 * ,这是为啥? 
猜测是,现在shell更智能了。

使用标准输入作为awk的输入

ls -l | awk ' $1 !~ /total/  { printf "%-32s %s\n", $9, $5 ; } '

变量:
可以直接将awk解析过的字段的值赋予变量
如:fruit=$1
给变量fruit赋予输入行的第一个字段的值
下面看一个在awk中变量与数值操作符(+,-,*,/,%,…,^)结合的使用

#!/bin/sh
#此脚本用于计算文件的空白行数
#如果变量没有定义,则awk就会创建这个变量
#并且给它赋值0
blank() {
for i in $@
do 
if [ -f $i ] ; then
echo $i
awk '/^ *$/ { x=x+1 ; print x ; }' $i
else
echo "Error: $i not a file" >&2
fi
done
}

blank now param.sh

另外,与C语言类似,awk中也具有精简模式的赋值符号
+=,-=,*=,/=, %= , ^=

特殊的样式匹配: BEGIN和END
在上述代码中,awk '/^ *$/ { x=x+1 ; print x ; }' $i
在x值每次增加的时候就打印一次。但可以使用BEGIN和END,在最后打印空行的总数

awk '
BEGIN { actions }
/pattern/ { actions }
/pattern/ { actions }
END { actions }
' files
当样式匹配BEGIN被指定时(必须是第一个指定匹配),awk在读入任何行之前执行它的actions,但如果一个程序只有一个BEGIN组成,则awk不会读取file。当样式匹配END被指定时(必须是最后一个匹配),awk在它退出之前执行actions.
改进上述脚本函数:

#!/bin/sh
#此脚本用于计算文件的空白行数
#如果变量没有定义,则awk就会创建这个变量
#并且给它赋值0
#注意next的使用
blank() {
for i in $@
do 
if [ -f $i ] ; then
echo $i
awk '
/^ *$/ { x=x+1 ; next ; }  
 END { printf " %s \n", x ; }
' $i
else
echo "Error: $i not a file" >&2
fi
done
}

blank now param.sh

awk中的内部变量

FILENAME     当前输入文件的名称,不能改变这个变量的值
NR                   当前输入文件的行数或者输入文件的记录。不能改变这个变量的值
NF                   当前行或者记录的字段数。不能改变这个变量的值
OFS                 输出字段的分隔符(默认是空格)
FS                   输入字段的分隔符(默认是空格和制表符)
OFMT             数字的输出格式(默认是%.6g)
ORS                 输出记录分隔符(默认是新起一行)
RS                   输入记录分隔符(默认是新起一行)

1.使用 FILENAME 和 NR

#!/bin/sh
#此脚本用于计算文件的空白行数
#如果变量没有定义,则awk就会创建这个变量
#并且给它赋值0
#注意next的使用
blank( ) {
for i in $@
do 
if [ -f $i ] ; then
echo $i
awk '
/^ *$/ {file=FILENAME ; x=x+1 ; next ; }  
 END { printf " %s %s%3.1f\n",file, x ,(100 * ( x / NR ) ) ; }
' $i
else
echo "Error: $i not a file" >&2
fi
done
}

blank now param.sh

注意百分比的值是小数或者浮点数。awk把所有的数字都看作浮点数,并且所有
计算返回的值均为浮点值

2.改变输入字段分隔符

输入字段分隔符FS,控制着awk怎样把一个输入行分为几个字段。有如下两种方式更改:
FS默认是空格和制表符,现在我们将其更换为 :
在BEGIN中手工重置:   BEGNIN { FS=": "; }
给awk指定 -F 选项: awk -F: '{……}'
两种方法之间的主要不同在于,-F选项可以类似使用shell变量去动态地指定分隔符:
$ MYFS=: ; export MYFS ; awk -F${MYFS} '{……}'

3.让awk使用shell变量

awk 'script'  awkvar1=value awkvar2=value ..... files

看下面的代码例子:

#!/bin/sh
NUMFRUIT="$1"
if [ -z "$NUMFRUIT"  ] ; then NUMFRUIT=75 ; fi

awk '
$3 <= numfruit {print ;}
' numfruit="$NUMFRUIT" fruit_prices

只有那些小于指定数目的行的才被打印

awk中右3种主要形式的流程控制:
if语句,while语句,for语句。
awk '流程控制语句' files

这三种流程语句皆是用C语言表达形式

看几个例子:
#!/bin/sh
#认为下面这个代码写的太罗嗦
#用以标记单价大于1,重量小于75单位的水果。
awk '{
if ( $2 ~/\$[1-9]*\.[0-9][0-9]/ ) {
printf( "%s\t%s", $0, "*") ;
if ( $3 <= 75 ) {
printf "REORDER\n";
}
else {
printf "\n"  ;
}
}
else {
if ( $3 <= 75 ) {
printf( "%s\t%s",$0, "REORDER\n") ;
}
else {
printf( "%s\n", $0 ) ;
}
}
}' fruit_prices

#替换一下
#这样还真不可以,因为这样就只打印符合两个条件的内容了
awk '{
if ( $2 ~/\$[1-9]*\.[0-9][0-9]/ ) 
printf( "%s\t%s", $0, "*") ;

if ( $3 <= 75 ) {
printf "REORDER\n";
}
else {
printf "\n"  ;
}
}' fruit_prices

while 语句
while (expr) {
actions ;
}
#用NF来访问当前记录的字段数
awk '{
x=NF ;
while (x>0) {
printf( "%16s",$x ) ;
x-=1 ; 
}
print "" ;
}' fruit_prices
#end

#do语句的应用
awk '{
x=NF ; 
do {
printf( "%16s", $x ) ; 
x-=1 ;
} while(x>0) ;
print "" ;
}' fruit_prices

for 语句

#for语句的应用
awk '{
for ( x=NF ; x>0 ; x-=1 )
 printf ( "%16s", $x ) ;
printf "\n" ; 
}' fruit_prices

awk '{
for (x=1 ; x<=NF ; x+=1 )
 printf ( "%16s", $x ) ;
printf "\n" ;
}' fruit_prices 

awk是UNIX中最强大的文本过滤工具之一。通过使用awk,可以以只使用shell实现起来非常困难甚至
不可能的方法修改和转换文本。


阅读(1501) | 评论(0) | 转发(0) |
0

上一篇:学习shell笔记(3)

下一篇:latex 希腊字母

给主人留下些什么吧!~~