@AWK的格式@
注意一:BEGIN{写在同一行,END{写在同一行。
Awk-F"\t" 'BEGIN{ #BEGIN{必须写在一行,并且必须写在起始行。
}
$1==1&& $2==2 && $3==3{ #&&之间的空格可以省略
}
END{ #END{必须写在一行,
}'
'
注意二: AWK的管道只能被打开一次
BEGIN是初始化,在读文件之前进行,END是扫尾,在读文件之后进行。
@AWK的执行方式@
方式一 $ awk-f pay1.awk emp.dat
方式二 $ awk'{ print $2, $3 * $4 }' emp.dat
@AWK 的工作流程 @
执行 awk 时, 它会反复进行下列四步骤.
1. 自动从指定的数据文件中读取一个数据行.
2. 自动更新(Update)相关的内建变量之值. 如 : NF, NR,$0...
3. 依次执行程序中 所有 的 Pattern { Actions } 指令,其中Pattern { Actions } 的语法已涵盖这种 " if ( 条件) { 动作} "的架构。
4. 当执行完程序中所有 Pattern {Actions } 时, 若数据文件中还有未读取的数据, 则反复执行步骤1 到步骤4.
awk 会自动重复进行上述4 个步骤, 使用者不须于程序中编写这个循环 (Loop).
@内建变量@
$0,一字符串, 其内容为目前 awk 所读入的数据行.
$1,$0 上第一个字段的数据.
$2,$0 上第二个字段的数据.
$n,$0 上第n个字段的数据.
$NF (Numberof Fields) 为一整数, 其值表$0 上所存在的字段数目.
$NR (NumberofRecords)为一整数, 其值表awk 已读入的数据行数目.
$FILENAME
$FS 例如,FS ="[\t:]+" (改变字段分隔符,使它变为空格或者tab或者冒号。)
数组:使用字符串当数组的下标(index),类似关联数组使用数组前不须宣告数组名及其大小.
[例1]
例如 : awk 从资料文件 emp.dat 中读入第一笔数据行
"A125Jenny 100 210" 之后, 程序中:
$0 之值将是 "A125Jenny 100 210"
$1 之值为"A125"
$2 之值为"Jenny"
$3 之值为 100
$4 之值为 210
$NF 之值为 4
$NR 之值为 1
$FILENAME 之值为"emp.dat"
注意:在awk 中任何变量使用之前, 并不须事先声明. 其初始值为空字符串(Null string)或 0.
@读取命令行的参数@
建立文件如下, 命名为 see_arg :
#!/bin/sh
awk '
BEGIN {
for( i=0;i<ARGC ; i++)
print ARGV[i]# 依次印出awk 所记录的参数
}
' $*
执行: $ ./see_argfirst-arg second-arg
结果:
awk
first-arg
second-arg
@实例之哈希应用@
需求:分析apace日志,获取访问量较大的前十个IP地址
方法: awk‘{ips[$1]++;}END{for(ip in ips)print ip,ips[ip]}’ |sort –nk2|head -10
实例结果分析:该apace日志首列保存ip信息。能过awk对日志进行一次遍历,即实现了IP信息的获取,同时采用了哈希结构,对ip进行了累计。
@OFS为什么不起作用@
echo 'aaa bbbccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd' |awk -v OFS="|" '{print $0}'
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
上面的例子中OFS为什么没有生效呢,原因是OFS指的是输出字段分隔符,所以必须对字段进行操作时OFS才会起作用,正确的方法应该是:
echo 'aaa bbbccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd
aaa bbb ccc ddd' |awk -v OFS="|" '{$1=$1;print $0}'
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
aaa|bbb|ccc|ddd
正如Tim大师所讲的,$1=$1这个action,是我们对awk撒的谎,目的就是为了使得OFS生效,除此之外,NF+=0也是常用的方法
@如何让awk匹配变量呢?@
PATTERNFILE=($(cat$1))
iter3=0
while [ "$iter3" -lt ${#PATTERNFILE[@]} ]
do
PATTERN=${PATTERNFILE[$iter3]}
cat /admin/inputdata/*|awk -F"\t" -v pattern_awk=$PATTERN'$16~pattern_awk{print $16}'>>geturl.result.txt
echo"#############################################">>geturl.result.txt
iter3=$(($iter3+1))
done
@从文件中读入数据@
while readLINE
do
echo"LINE : $LINE"
done <auto.sh
@内建函数-index@
index( 原字串, 找寻的子字串 )
若原字串中含有欲找寻的子字串,则返回该子字串在原字串中第一次出现的位置,若未曾出现该子字串则返回0.
执行 :
$ awk 'BEGIN{print index("8-12-94","-") }'
结果:2
@内建函数-index@
length( 字串 ) : 返回该字串的长度
@内建函数-match@
match( 原字串, 用以找寻比对的正则表达式 ),awk 找到该字串后会依此字串为依据进行下列动作:设定awk 内建变量 RSTART,RLENGTH,并返回 RSTART 之值。
RSTART
= 合条件的子字串在原字串中的位置.
= 0 ; 若未找到合条件的子字串.
RLENGTH
= 合条件的子字串长度(贪婪匹配)
= -1 ; 若未找到合条件的子字串.
[例1]
awk ' BEGIN {
match("banana", /(an)+/ )
print RSTART,RLENGTH
} '
结果: 2 4
@内建函数-split@
split( 原字串, 数组名称, 分隔字符 )
awk 将依所指定的分隔字符(fieldseparator)来分隔原字串成一个个的栏位(field),并以指定的数组记录各个被分隔的栏位.
[例1]:
ArgLst ="5P12p89"
split(ArgLst, Arr, /[Pp]/)
执行结果 : Arr[1]=5,Arr[2]=12, Arr[3]=89
sub( 比对用的正则表达式, 将替换的新字串, 原字串 )
[例1]
A ="a6b12anan212.45an6a"
sub(/(an)+[0-9]*/, "[&]", A)
print A
结果输出
ab12[anan212].45an6a
总结:第二个参数"将替换的新字串"中可用"&"来代表"合於条件的子字串"
[例2]
awk '
BEGIN {
data ="p12-P34 P56-p61"
while( match(data ,/[0-9]+/) > 0) {
printsubstr(data, RSTART, RLENGTH )
sub(/[0-9]+/,"",data)
}
}'
总结:通过 sub() 与 match() 的搭配使用,可逐次取出原字串中合乎指定条件的所有子字串.
结果输出
12
34
56
61
substr( 字串,起始位置 [,长度] )
[例1]
$ awk 'BEGIN{ print substr("User:Wei-Lin Liu", 6)}'
结果印出
Wei-Lin Liu
[例2]从文件的 Fullname 中分离出路径 与 档名
awk '
BEGIN{
Fullname ="/usr/local/bin/xdvi"
match(Fullname, /.*\//)
path = substr(Fullname,1, RLENGTH-1)
name =substr(Fullname, RLENGTH+1)
print"path :", path," name :",name
}
' $*
结果印出
path :/usr/local/bin name : xdvi
printf
TIME=`date+%H" "%M|awk '{m=int($2/10)*10; printf("%02d%02d",$1,m)}'`
注意格式控制,printf("%02d%02d",$1,m)中的02d说明是2位数的整数。
@awk中的时间处理@
mktime( YYYYMM DD HH MM SS[ DST])生成时间
strftime([format[, timestamp]])格式化时间输出,将时间戳(从1970年1月1日开始到当前时间(不计闰年)的整秒数)转为时间字符串
[ixigua@SuSE ~]$ awk 'BEGIN{tstamp=mktime("2001 0101 12 12 12");print strftime("%c",tstamp);}'
2001年01月01日 星期一 12时12分12秒
[ixigua@SuSE ~]$ awk 'BEGIN{tstamp1=mktime("2001 01 01 12 1212");tstamp2=mktime("2001 02 01 0 0 0");print tstamp2-tstamp1;}'
2634468
[ixigua@SuSE ~]$ awk 'BEGIN{tstamp1=mktime("2001 01 01 12 1212");tstamp2=systime();print tstamp2-tstamp1;}'
308201392