zoukankan      html  css  js  c++  java
  • 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
    A 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
    line2 f4 f5
    line3 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键值。
    #删除键值:
    [chengmo@localhost ~]$ 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(34)作为分割字段,在上面的例子中,关联数组array存储的键值实际上是2344。

    类似一维数组的成员测试,多维数组可以使用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
    ",n1,n2,n3,n4)}'
    12.35,100,test      ,18446744073709551516
  • 相关阅读:
    机器学习入门实践——线性回归&非线性回归&mnist手写体识别
    基于OpenCV的摄像头采集印刷体数字识别
    使用rviz实现本地计算机绘制机器人路径
    从0开始的FreeRTOS(4)
    从0开始的FreeRTOS(3)
    从0开始的FreeRTOS(2)
    从0开始的FreeRTOS(1)
    Robomaster电控入门(8)RTOS
    Robomaster电控入门(7)双轴云台控制
    计算机与网络课程设计开发纪要
  • 原文地址:https://www.cnblogs.com/shaozi/p/8395368.html
Copyright © 2011-2022 走看看