前言
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。
一、awk命令格式和选项
awk [options] ‘script‘ file
常用命令选项
-F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
-v var=value 赋值一个用户定义变量,将外部变量传递给awk
-f scripfile 从脚本文件中读取awk命令
二、awk脚本基本结构
awk ‘BEGIN{ print "start" } pattern{ commands } END{ print "end" }‘ file
一个awk脚本通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块3部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中,例如:
awk ‘BEGIN{ i=0 } { i++ } END{ print i }‘ filename awk "BEGIN{ i=0 } { i++ } END{ print i }" filename
awk工作原理:
- 第一步:执行
BEGIN{ commands }
语句块中的语句; - 第二步:从文件或标准输入(stdin)读取一行,然后执行
pattern{ commands }
语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。 - 第三步:当读至输入流末尾时,执行
END{ commands }
语句块。
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。
END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。
pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print }
,即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
例如:
echo -e "A line 1\nA line 2" | awk ‘BEGIN{ print "Start" } { print } END{ print "End" }‘ Start A line 1 A line 2 End
当使用不带参数的print
时,它就打印当前行,当print
的参数是以逗号进行分隔时,打印时则以空格作为定界符。在awk的print语句块中双引号是被当作拼接符使用,例如:
echo | awk ‘{ var1="v1"; var2="v2"; var3="v3"; print var1,var2,var3; }‘ v1 v2 v3
双引号拼接使用:
echo | awk ‘{ var1="v1"; var2="v2"; var3="v3"; print var1"="var2"="var3; }‘ v1=v2=v3
三、awk内置变量
$n 当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。
$0 这个变量包含执行过程中当前行的文本内容。
FS 字段分隔符(默认是任何空格)。
NR 表示记录数,在执行过程中对应于当前的行号。
OFMT 数字的输出格式(默认值是%.6g)。
OFS 输出字段分隔符(默认值是一个空格)。
ORS 输出记录分隔符(默认值是一个换行符)。
RS 记录分隔符(默认是一个换行符)。
例如:
echo -e "line1 f2 f3\nline2 f4 f5\nline3 f6 f7" | awk ‘{print "Line No:"NR", No of fields:"NF, "$0="$0, "$1="$1, "$2="$2, "$3="$3}‘ Line No:1, No of fields:3 $0=line1 f2 f3 $1=line1 $2=f2 $3=f3 Line No:2, No of fields:3 $0=line2 f4 f5 $1=line2 $2=f4 $3=f5 Line No:3, No of fields:3 $0=line3 f6 f7 $1=line3 $2=f6 $3=f7
将外部变量值传递给awk,借助-v
选项,可以将外部值(并非来自stdin)传递给awk:
VAR=10000 echo | awk -v VARIABLE=$VAR ‘{ print VARIABLE }‘
四、流程控制语句
if条件判断语句
if(表达式) 语句1 else 语句2
if(表达式) {语句1} else if(表达式) {语句2} else {语句3}
例如:
awk ‘BEGIN{ test=100; if(test>90){ print "very good"; } else if(test>60){ print "good"; } else{ print "no pass"; } }‘ very good
while语句
while(表达式) {语句}
例如:
awk ‘BEGIN{ test=100; total=0; while(i<=test){ total+=i; i++; } print total; }‘ 5050
for语句
格式1:
for(变量 in 数组) {语句}
例如:
awk ‘BEGIN{ arry[1]="a"; arry[2]=2; for(k in arry){ print arry[k]; } }‘ a 2
格式2:
for(变量;条件;表达式) {语句}
例如:
awk ‘BEGIN{ total=0; for(i=0;i<=100;i++){ total+=i; } print total; }‘ 5050
do语句
do {语句} while(条件)
例如:
awk ‘BEGIN{ total=0; i=0; do {total+=i;i++;} while(i<=100) print total; }‘ 5050
五、数组应用
数字做数组索引(下标):
Array[1]="sun" Array[2]="kai"
字符串做数组索引(下标):
Array["first"]="www" Array["last"]="name" Array["birth"]="1987"
读取数组的值:
{ for(item in array) {print array[item]}; } #输出的顺序是随机的 { for(i=1;i<=len;i++) {print array[i]}; } #Len是数组的长度
得到数组长度:
awk ‘BEGIN{info="it is a test";lens=split(info,tA," ");print length(tA),lens;}‘ 4 4
#length返回字符串以及数组长度,split进行分割字符串为数组,也会返回分割得到数组长度。
输出数组内容(无序,有序输出):
awk ‘BEGIN{info="it is a test";split(info,tA," ");for(k in tA){print k,tA[k];}}‘ 4 test 1 it 2 is 3 a
#for…in
输出,因为数组是关联数组,默认是无序的。所以通过for…in
得到是无序的数组。如果需要得到有序数组,需要通过下标获得。
awk ‘BEGIN{info="it is a test";tlen=split(info,tA," ");for(k=1;k<=tlen;k++){print k,tA[k];}}‘ 1 it 2 is 3 a 4 test
#注意:数组下标是从1开始,与C数组不一样。
判断键值存在以及删除键值:
#错误的判断方法: awk ‘BEGIN{tB["a"]="a1";tB["b"]="b1";if(tB["c"]!="1"){print "no found";};for(k in tB){print k,tB[k];}}‘ no found a a1 b b1 c
#以上出现奇怪问题,tB[“c”]
没有定义,但是循环时候,发现已经存在该键值,它的值为空,这里需要注意,awk数组是关联数组,只要通过数组引用它的key,就会自动创建改序列。
#正确判断方法: awk ‘BEGIN{tB["a"]="a1";tB["b"]="b1";if( "c" in tB){print "ok";};for(k in tB){print k,tB[k];}}‘ a a1 b b1
#if(key in array)
通过这种方法判断数组中是否包含key
键值。
#删除键值: [[email protected] ~]$ awk ‘BEGIN{tB["a"]="a1";tB["b"]="b1";delete tB["a"];for(k in tB){print k,tB[k];}}‘ b b1
#delete array[key]
可以删除,对应数组key
的,序列值
六、二维数组
awk的多维数组在本质上是一维数组,更确切一点,awk在存储上并不支持多维数组。awk提供了逻辑上模拟二维数组的访问方式。例如,array[2,4]=1
这样的访问是允许的。awk使用一个特殊的字符串SUBSEP(\034)
作为分割字段,在上面的例子中,关联数组array存储的键值实际上是2\0344。
类似一维数组的成员测试,多维数组可以使用if ( (i,j) in array)
这样的语法,但是下标必须放置在圆括号中。类似一维数组的循环访问,多维数组使用for ( item in array )
这样的语法遍历数组。与一维数组不同的是,多维数组必须使用split()
函数来访问单独的下标分量。
例如:
awk ‘BEGIN{ for(i=1;i<=3;i++){ for(j=1;j<=3;j++){ tarr[i,j]=i*j; print i,"*",j,"=",tarr[i,j]; } } }‘
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
3 * 1 = 3
3 * 2 = 6
3 * 3 = 9
另一种方法:
awk ‘BEGIN{ for(i=1;i<=3;i++){ for(j=1;j<=3;j++){ tarr[i,j]=i*j; } } for(m in tarr){ split(m,tarr2,SUBSEP); print tarr2[1],"*",tarr2[2],"=",tarr[m]; } }‘
3 * 3 = 9
1 * 1 = 1
2 * 1 = 2
1 * 2 = 2
3 * 1 = 3
2 * 2 = 4
1 * 3 = 3
3 * 2 = 6
2 * 3 = 6
七、常用内置函数
length [(String)]:返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。
例如:
awk ‘BEGIN{info="test";print length(info)}‘ 4
substr( String, M, [ N ] ):返回从起始位置起,指定长度之子字符串;若未指定长度,则返回从起始位置到字符串末尾的子字符串。
例如:
awk ‘BEGIN{info="desk";print substr(info,2,3)}‘ esk
split( String, A, [Ere] ):awk的内建函数split允许你把一个字符串分隔为单词并存储在数组中。你可以自己定义域分隔符或者使用现在FS(域分隔符)的值。
例如:
awk ‘BEGIN{info="it:is:a:test";split(info,tA,":");for(k in tA){print k,tA[k];}}‘ 4 test 1 it 2 is 3 a
时间函数:
mktime( YYYY MM dd HH MM ss[ DST]):生成时间格式。例如:
awk ‘BEGIN{tstamp=mktime("2017 01 01 12 12 12");print strftime("%Y-%m-%d %H:%M:%S",tstamp);}‘ 2017-01-01 12:12:12
strftime([format [, timestamp]]):格式化时间输出,将时间戳转为时间字符串。例如:
awk ‘BEGIN{tstamp=mktime("2017 01 01 12 12 12");print strftime("%Y-%m-%d %H:%M:%S",tstamp);}‘ 2017-01-01 12:12:12
systime():得到时间戳,返回从1970年1月1日开始到当前时间(不计闰年)的整秒数。例如:
awk ‘BEGIN{time=systime();print time}‘ 1517496432
strftime日期和时间格式说明符
格式 | 描述 |
---|---|
%a | 星期几的缩写(Sun) |
%A | 星期几的完整写法(Sunday) |
%b | 月名的缩写(Oct) |
%B | 月名的完整写法(October) |
%c | 本地日期和时间 |
%d | 十进制日期 |
%D | 日期 08/20/99 |
%e | 日期,如果只有一位会补上一个空格 |
%H | 用十进制表示24小时格式的小时 |
%I | 用十进制表示12小时格式的小时 |
%j | 从1月1日起一年中的第几天 |
%m | 十进制表示的月份 |
%M | 十进制表示的分钟 |
%p | 12小时表示法(AM/PM) |
%S | 十进制表示的秒 |
%U | 十进制表示的一年中的第几个星期(星期天作为一个星期的开始) |
%w | 十进制表示的星期几(星期天是0) |
%W | 十进制表示的一年中的第几个星期(星期一作为一个星期的开始) |
%x | 重新设置本地日期(08/20/99) |
%X | 重新设置本地时间(12:00:00) |
%y | 两位数字表示的年(99) |
%Y | 当前月份 |
%Z | 时区(PDT) |
%% | 百分号(%) |
八、格式化输出
格式 | 描述 |
---|---|
%d | 十进制有符号整数 |
%u | 十进制无符号整数 |
%f | 浮点数 |
%s | 字符串 |
%c | 单个字符 |
%p | 指针的值 |
%e | 指数形式的浮点数 |
%x | %X 无符号以十六进制表示的整数 |
%o | 无符号以八进制表示的整数 |
%g | 自动选择合适的表示法 |
例如:
awk ‘BEGIN{n1=12.345;n2=100.12;n3="test";n4=-100.23;printf("%.2f,%d,%-10s,%u\n",n1,n2,n3,n4)}‘ 12.35,100,test ,18446744073709551516