美文网首页
Linux之GAS: awk小记

Linux之GAS: awk小记

作者: 齐州读经客 | 来源:发表于2018-04-30 22:59 被阅读18次

    1 说明

    man awk:
    awk - pattern scanning and processing language

    awk的名字来源于三位创始人的姓氏:Alfred Aho,Peter Weinberger, 和 Brian Kernighan。类似sed,awk每次读取一行为进行处理,但处理的最小单位是字段(也就是列,通常使用空格或制表符分隔),因此适合处理表格一类的数据。但同时awk不止是一个程序/命令,还是一门程序设计(脚本式的)语言,常应用于各种计算和数据处理任务。

    参考资料

    2 基本

    awk命令的基本形式:

    awk [options] SCRIPT [file]
    

    SCRIPT结构:
    脚本通常分为三部分,其中BEGIN,END部分是可选部分;当只有BEGIN部分是可以没有输入文件。其中:

    • BEGIN的action会在输入开始之前执行;
    • ENG的action会在所有行处理之后执行。

    另外,awk作为编程语言,可以定义函数,可以包含注释(通常在文件中,以保持可读性和可重用性),使用#注释该字符所在的行(不包括之前的字符)。

    BEGIN {action}
    pattern {action}
    END {action}
    

    awk处理的基本流程:

    1. 按行读取(从文件或标准输入等),每一行称为一条记录record,使用$0表示;
      1.1 当文件缺省时,从标准输入中读取;使用Ctrl+D终止程序
    2. 对每一行执行SCRIPT,包括检查是否满足pattern,满足则执行action部分;其中:
      2.1 pattern省略是表示没有条件限制;
      2.2 action省略是表示执行{print}即打印当前记录,两者不可同时省略。

    选项

    常用的选项包括:

    • -f progfile; --file=progfile 从file中读取awk指令。
    • -F fs; --field-separator=fs 指定分隔符:
    awk -F: '{print $1, $NF}' file.txt
    # -F后的内容是正则表达式形式
    awk -F '[.,:]' '{print $1, $NF}' file.txt
    
    • -v var=val; --assign=var=val 设定变量
    awk -v n=5 'BEGIN{for(i=0;i<n;i++) printf "%02d\n",i}'
    
    • -d[=file]; --dump-variables[=file] 输出排序后的全局变量和值;默认文件输出文件是awkvars.out
    • -p[file]; --profile[=file] 格式化awk程序,默认输出的文件是awkprof.out
    awk --profile 'BEGIN{printf"---|Header|--\n"} {print} 
    END{printf"---|Footer|---\n"}' marks.txt > /dev/null 
    

    其他选项

    • -V, --version 版本信息
    • --help 帮助信息

    SCRIPT之使用pattern过滤

    • pattern部分可以由多个正则表达式或算式由逻辑运算符连接而成
    • pattern之间可以使用,分隔,表示两个匹配模式之间的记录

    例子:

    awk 'BEGIN{print "----"} {print $1} END{print "-----"}'
    awk '/^root/,/^adm/' /etc/passwd   
    

    SCRIPT之使用action执行

    pattern之后的{}的内容表示 action;当actiono多个时可以使用;或换行进行分隔。

    这里先简单介绍print:
    print表示输出,期间可以使用$数组, 字符串需要使用引号包围。

    • 字段之间使用空格或,进行分隔
    • 可以重定向输出>>>保存输出
      此外还有格式化输出的printf
      另外awk中自定义变量,使用=进行赋值(直接使用,不需要向shell一样使用$标志),数组,条件语句等。详细的见【程序设计部分】。

    例子:

    # $5即文件大小字段,$NF即文件名字段
    # && 逻辑与;`/../`表示正则表达式; ~表示匹配
    ls -l *|awk '$5>20 && $NF ~ /txt$/'
    
    # 列出第1,3列
    last -n 5 | awk '{print $1 "\t" $3}'
    
    # 设置分隔符是:, 第3列值小于10是打印第1列(账号)和第3列(UID)
    cat /etc/passwd | awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'
    # 增加显示第一行(root);默认第一行是字段说明所以不直接处理
    cat /etc/passwd | awk 'BEGIN{FS=":"} $3 < 10 {print $1 "\t " $3}'
    
    # 复杂例子;从文件中读取awk
    # test.awk中的内容
    BEGIN{
        $1=1
        $2=1
        OFS=","
        for(i=3;i<=10;i++)
        {
            $i=$(i-2)+$(i-1)
        }
        print
    }
    # 打印斐波那契数列前10项
    awk -f test.awk
    
    # 定义变量
    awk '{a=$1} {print a,$5}' file.txt
    awk -v a="name" '{print a}'
    
    # 使用数组
    $ awk -F ':' '{a[$NF]++}END{for(i in a) print i,a[i]}' /etc/passwd
    
    # 使用条件语句
    netstat -antp | awk '{if($6=="LISTEN"){x++}else{y++}}END{print x,y}'
    

    3 程序设计

    内建变量

    内建变量 说明
    $0 当前处理记录(即当前读取的一行内容)
    $1-$n 当前记录的第n个字段(列)
    FS 字段/列分隔符,默认是空格或制表符
    NF 当前记录的字段数目
    NR 已经处理的记录条数,即当前行号
    FNR 当前记录数,是每个文件的行号,NR是总数
    RS 记录/行之间分隔符,默认是换行符\n
    CONVFMT 数字转换格式 %.6g
    OFS 输出字段分隔符,默认是空格
    ORS 输出记录分隔符,默认是换行符\n
    FIELDWIDTHS 输入字段宽度的空白分隔字符串
    OFMT 数字的输出格式,%.6g
    ARGC 命令行参数个数
    ARGV 命令行参数数组
    FILENAME 当前输入文件名字
    ARGIND 当前被处理文件的ARGV标志符
    ENVIRON UNIX/SHELL环境变量,数组形式
    ERRNO UNIX系统错误消息
    RSTART 被匹配函数匹配的字符串首
    RLENGTH 匹配函数匹配的字符串长度
    IGNRECASE 记录为真代表忽略大小写匹配
    SUBSEP \0340x1C;文件分割符)
    PROCINFO 当前运行程序进程信息数组

    此外还有一些GNU awk扩展: 略

    运算符

    基本和C语言一致,基本的有:

    • 赋值:=
    • 算术运算符:+-*/%;单目 ++, --, -(相反数), ^(指数)
    • 关系运算符:>, >=, <, <=, ==, !=
    • 逻辑运算符:&&, ||, !; 常在条件、循环等语句中使用
    • 三目:(a>b)? max=a:max=b;
    • 字符串连接:str3 =str1 str2
    • 数组:[]成员操作符
      • 数字索引的数组(可以不连续),字符串索引的数组(类似字典);
        不需要预先声明
    • 正则:~!~分别表示匹配和不匹配: $0 ~ /[a-z]/
      • 正则表达式:需要使用斜杠/对表达式进行包围

    例子:

    awk 'BEGIN { a = 50; b = 20; print "(a + b) = ", (a + b) }'
    

    控制语句

    • 条件语句: if-else
    • 循环语句:for, while
    • {}表示语句块,可以进一步嵌套

    例子:来自

    #  计算复利
    #   输入: 钱数    利率    年数
    #   输出: 复利值
    {   i = 1
        while (i <= $3) {
            printf("\t%.2f\n", $1 * (1 + $2) ^ i)
            i = i + 1
        }
    }
    

    用户自定义函数

    function function_name(argument1, argument2, ...) { 
       function body
    }
    

    例子:来自

    # 脚本文件
    # Returns minimum number
    function find_min(num1, num2){
       if (num1 < num2)
       return num1
       return num2
    }
    # Returns maximum number
    function find_max(num1, num2){
       if (num1 > num2)
       return num1
       return num2
    }
    # Main function
    function main(num1, num2){
       # Find minimum number
       result = find_min(10, 20)
       print "Minimum =", result
      
       # Find maximum number
       result = find_max(10, 20)
       print "Maximum =", result
    }
    # Script execution starts here
    BEGIN {
       main(10, 20)
    }
    

    调用外部shell程序/命令

    • 管道
    • system函数

    例子:

    # 管道方式
    while (more stuff to do)
        print command | "/bin/sh"
    close("/bin/sh")
    
    # system函数
    END { system("date | mail -s 'awk run done' root")}
    

    4 内建函数

    数学相关函数

    • exp, log
    • int, sqrt,
    • rand, srand
    • sin, cos, atan2

    字符串相关

    • length() 获得字符串长度
    awk -F: '{if(length($1)>=16) print}' /etc/passwd 
    
    • split()将字符串按分隔符分隔,并保存至数组
    head -1 /etc/passwd|awk '{split($0,arr,/:/);for(i=1;i<=length(arr);i++) print arr[i]}'
    
    • sub(regex,substr,string) 替换string中匹配regex的第一项为substr;string为空则默认是$0;
    echo 178278 world | awk 'sub(/[0-9]+/,"hello")'
    
    • gsub: 类似sub,全部替换
    • substr
    • tolower
    • match

    时间

    • systime
    • mktime(datespec)
    • strftime([format [, timestamp[, utc-flag]]])

    bit操作

    • and, or, xor
    • compl(val): Return the bitwise complement of val.
    • 移位 lshift, rshift

    其他(IO等)

    • close(expr) 关闭管道文件
    • delete 删除数组元素
    • exit 退出脚本执行并返回状态码
    • getline 读取下一行内容
    • next
    • return
    • system(cmd) 执行外部shell的cmd命令,返回的结果0表示成功

    相关文章

      网友评论

          本文标题:Linux之GAS: awk小记

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