awk命令介绍

Posted 元朗蛋卷

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了awk命令介绍相关的知识,希望对你有一定的参考价值。

前言

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

 

以上是关于awk命令介绍的主要内容,如果未能解决你的问题,请参考以下文章

Linux awk命令简单介绍

awk命令介绍

awk命令详解二

awk命令

linux awk 内置变量使用介绍

shell编程awk基础介绍