七.Linux之awk命令

作者: Dakini_Wind | 来源:发表于2019-01-31 13:08 被阅读7次

    awk的调用方式与sed类似,脚本文件以#!/bin/awk -f或#!/bin/gawk -f开头。相比于grep和sed,awk正则表达式支持"?"和"+"两个拓展元字符。

    • awk模式匹配
    $ cat file 
    qwer
    
    
    1234
    [jin1ming@ML linux_shell]$ awk '/^$/{print "Hello World!"}' file 
    Hello World!
    Hello World!
    

    ^$在此处用于匹配空行

    • 记录和域
      awk认为每行为一个记录,行中每个字符串为域,域之间用空格,Tab键或其他符号进行分隔,分隔域的是分隔符。(分隔符默认为空格)
    $ cat phoneinfo 
    张三 湖南 123455
    李四 山西 222222
    王五 河南 333333
    $ awk '{print $1}' phoneinfo 
    张三
    李四
    王五
    $ awk '{print $1;{print $0}}' phoneinfo 
    张三
    张三 湖南 123455
    李四
    李四 山西 222222
    王五
    王五 河南 333333
    $ awk 'BEGIN{num=3} {print$num}' phoneinfo 
    123455
    222222
    333333
    

    n代表第n个域,0代表所有域
    awk处理时,将进行逐行扫描
    BEGIN在遍历文件前执行
    awk中可使用变量

    $ awk 'BEGIN{OFS=";"} {print $1,$2,$3}' phoneinfo | 
    > awk 'BEGIN{FS=";";OFS="::"} {print $1,$2,$3}'
    张三::湖南::123455
    李四::山西::222222
    王五::河南::333333
    

    OFS为输出域分隔符,FS为(输入)域分隔符
    该demo,将文件中的空格作为域分隔符进行域划分,
    将“;”作为域分隔符进行输出到管道,
    最后将管道中的文本按“;”作为域分隔符进行域划分,
    最后将“::”作为输出域分隔符进行输出。

    #修改字符串之间的空格为两个
    $ cat phoneinfo 
    张三  湖南  123455
    李四  山西  222222
    王五  河南  333333
    $ awk 'BEGIN{OFS=","}{print $1,$2,$3}' phoneinfo 
    张三,湖南,123455
    李四,山西,222222
    王五,河南,333333
    

    说明空格作为域分隔符时,空格可为1个或多个

    $ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
    > awk 'BEGIN{FS=":";OFS=","} {print $1,$2,$3}' 
    张三,,湖南
    李四,,山西
    王五,,河南
    $ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
    > awk 'BEGIN{FS="::";OFS=","} {print $1,$2,$3}' 
    张三,湖南,123455
    李四,山西,222222
    王五,河南,333333
    

    其他符号作为域分隔符只代表其一个字符,若想多个,必须使用“+”,
    例如 \t+代表一个或多个该字符(支持正则)
    注意此处第一个命令,输出中第二个域为空域

    $ awk 'BEGIN{OFS="::"}{print $1,$2,$3}' phoneinfo |
    > awk 'BEGIN{FS="::";OFS=",";ORS=";"}
    > {print $1,$2,$3}' 
    张三,湖南,123455;李四,山西,222222;王五,河南,333333;
    

    ORS输出域分隔符,RS记录分隔符(默认都为换行符)

    • 关系和布尔运算符

    需注意:
    1:~ 匹配正则表达式
    2: !~ 不匹配正则表达式
    其他运算符与c语言一致

    $ awk 'BEGIN{FS=":"} $2~/dd/' 2.txt 
    2:dd
    :ddddddd
    
    • 表达式
      统计行数
    $ awk 'BEGIN{i=0} {print ++i}' 2.txt 
    1
    2
    3
    4
    5
    

    计算每人平均分数

    $ cat score 
    张三:78 92 87
    李四:91 64 87
    王五:34 99 56
    $ cat awkdomo.awk 
    #!/bin/awk -f
    
    BEGIN {FS="[: ]"}
    {sum=$2+$3+$4
    avg=sum/3
    print $1,":",avg}
    
    $ chmod u+x awkdomo.awk 
    $ ./awkdomo.awk score 
    张三 : 85.6667
    李四 : 80.6667
    王五 : 63
    
    • 常用系统变量
      以上提到的不再重复

    ARGC 命令行参数的数量
    ARGIND 命令行中当前文件的位置(以0开始标号)
    ARGV 命令行参数的数组(ARGV[0]存储的是执行脚本的程序名)
    FILENAME 当前文件名
    NF 当前记录中的域数量

    $ cat awkdomo.awk 
    #!/bin/awk -f
    
    BEGIN{FS="[: ]"}
    
    {print "\nARGC:",$ARGC,
        "\nARGIND:",$ARGIND,
        "\nARGV",$ARGV[2],
        "\nFILENAME:",$FILENAME,
        "\nNF:",$NF
    }
    
    $ ./awkdomo.awk score 
    
    ARGC: 78 
    ARGIND: 张三 
    ARGV 张三:78 92 87 
    FILENAME: 张三:78 92 87 
    NF: 87
    
    ARGC: 91 
    ARGIND: 李四 
    ARGV 李四:91 64 87 
    FILENAME: 李四:91 64 87 
    NF: 87
    
    ARGC: 34 
    ARGIND: 王五 
    ARGV 王五:34 99 56 
    FILENAME: 王五:34 99 56 
    NF: 56
    
    • 格式化输出
      printf (格式控制符,参数) ,与c语言一致
    • 内置字符串函数

    gsub(r,s) 在输入文件中用s替换r(全局替换)
    gsub(r,s,t) 在t行中用s替换r
    index(s,t) 返回s中字符串第一个t的位置
    length(s) 返回s的长度
    match(s,t) 测试s是否包含匹配t的字符串
    split(r,s,t) 以t为分隔符将r进行分割,保存到数组s
    sub(r,s,t) 将t中第一次出现的r替换为s
    substr(r,s) 返回字符串r中从s开始的后缀部分
    substr(r,s,t) 返回字符串r中从s开始长度为t的后缀部分

    • 向awk脚本传递参数
      awk -f 脚本文件 parameter=value 输入文件

      awk [awk命令] parameter=value 输入文件
    $ awk '
    BEGIN{n = 999; print n}
    {if (n==1) print "Continue!"
    } ' n=1 2.txt
    999
    Continue!
    Continue!
    Continue!
    Continue!
    Continue!
    

    参数赋值在BEGIN后执行

    • 条件语句和循环语句
      和c语言完全一致,在判断时可以使用~匹配符和正则表达式作为if语句的条件
    • 数组
      awk数组的形式和c语言一致,只是无需定义就可以使用,需要注意的是数组下标不是必须为整数,可以为浮点数或字符串,而且09和9作为下标是不一样的
    $ awk '
    BEGIN{nums[1.5]=5.1} {print nums[1.5];print nums[1]} 
    ' score
    5.1
    
    5.1
    
    5.1
    
    $ awk '
    BEGIN{nums[wer]=9;nums[2]=2;nums[9]=9} 
    END {for (var in nums)
    print var,":",nums[var]
    }' score
     : 9
    9 : 9
    2 : 2
    
    

    数组和参数相结合的根据姓名查询个人信息

    $ cat awkdomo2.awk 
    #!/bin/awk -f
    
    BEGIN{
       if(ARGC>2){
           name=ARGV[1];
           delete ARGV[1] }
       else{
           while(!name){
               print "请输入姓名:";
               getline name< "-"}
           }
       }
    
       $1~name {print $1,$2,$3}
    ./awkdomo2.awk  张三 phoneinfo 
    张三 湖南 123455
    

    输入姓名使用read将会使得"请输入姓名:"疯狂输出,原因还尚未琢磨清楚

    相关文章

      网友评论

        本文标题:七.Linux之awk命令

        本文链接:https://www.haomeiwen.com/subject/frlksqtx.html