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) |