linux-awk

2017-05-11

来源:

  1. http://man.linuxde.net/awk
  2. 沈剑老师的公众号

awk是一种编程语言, 用于在linux、unix下对文本和数据进行处理, 数据可以来自标准输入(stdin), 一个或多个文件, 或其他命令输出, 它支持用户自定义函数和动态正则表达式等先进功能, 是linux/unix下的一个强大编程工具, 它在命令行中使用, 但更多是作为脚本来使用。awk有很多内建功能,比如数组、函数等, 这是它和C语言的相同之处, 灵活性是awk最大的优势。

awk命令格式和选项


原理:

逐行处理文件中数据

awk 'BEGIN{commands} pattern{commands} END{commands}'

**BEGIN语句块在awk开始从输入流读取行之前被执行, 这是一个可选的语句块, 比如变量初始化、打印表格表头等语句
**

**END语句块在awk从输入流读完所有的行之后被执行,比如打印所有行的分析结果这类信息汇总走势在END语句块中完成,他也是一个可选语句块
**

**pattern语句块中的通用命令是最重要的部分,直接作用于文件的每一行数据,它也是可选的, 如果没有提供pattern语句块,则默认执行{print}, 打印每一行
**

语法:

awk 'pattern + {action}'
# awk '模式 + {操作}' 模式可以省略, 将模式写入{command}中
awk 'NR==20{print $1, $2}'
awk '{if(NR==20)print $1, $2}'

说明:

  • 单引号 是 为了和shell命令区分开
  • **大括号{}标识一个命令分组 **
  • pattern是一个过滤器, 表示命中pattern的行才能进行action操作 BEGIN等语句在pattern中
  • atcion是处理动作
  • 使用#作为注释

常用命令选项:

  • -F fs fs指定分割符,默认空格,fs可以是字符串或正则表达式,如-F:

  • -v var=value 复制一个用户定义变量, 将外部变量传递给awk

  • -f scripfile 从脚本文件中读取awk命令

  • -m[fr] val 对val值设置内在限制(标准awk不适用)

    -mf 设置给val的最大块数目

    -mr 限制记录的最大数目

模式:

  • /正则表达式/ : 使用通配符的扩展集
  • 关系表达式: 字符串或数字比较操作 == 、!= 、 > 、 => 等
  • 模式表达式: ~(匹配于) 、 ~!
  • BEGIN / pattern / END语句块:

操作:

**操作是由一个或多个命令、函数、表达式组成,之间由换行符或者分号隔开,并位于{}内**
  • 变量或者数组赋值

    • 赋值 count=0

    • 数组:

        #awk数组不必提前声明,也不必声明大小, 数组元素用0或者空字符串来初始化, 这根据上下文而定, awk数组可以用数字或者字符串作为下标(其实类似python、java中字典)
      
        Array[1]="sun"
        Array[2]="kai"
        Array["first"]="www"
        Array["last"]="name"
        
        #读取数组的值
        
        {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           
        awk 'BEGIN{info="it is a test";lens=split(info, tA, " ");print asort(tA);}'
        # asort对数组排序函数, 本身也返回数组长度(asort函数没定义???)
        
        # 数组读取
        
        awk 'BEGIN{info="it is a test";lens=split(info, tA, " ");for(k in tA){print k, tA[k];}}'
        # 随机输出  for k in tA  k是键值, 这点和python字典中一样
        # 2 is
        # 3 a
        # 4 test
        # 1 it
        
        awk 'BEGIN{info="it is a test";lens=split(info, tA, " ");for(k=1;k<=lens;k++)print k, tA[k];}'
        # 按顺序输出, 很像C语言,有木有,一样的;结束,一样的大括号战役(只有一句可以省略{},但是操作外面的{}必须有), 但是注意数组下标从1开始
        
        # 啊? 如果想删除数组的键值怎么办(数组这个词怪怪的,类似字典)
        delete Array['a']
        
        #判断是否包含
        if("a" in Array) print "ok"         
        
        ## 二维数组: 除了不用预先声明外, 赋值神马的和C语言一样
      
  • 输出命令

  • 内置函数

    • gsub(Ere, Repl, String): 在String, 用Repl替换掉Ere, 原位置替换,String被改变

        awk '{gsub(r, s)}'      # 在$0中用s替代r,  默认Sring=$0
        
        awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/, "!", info);print info}'
      
    • index(s, t): 返回s中t的第一个位置, 没有找到回0

    • length(s): s的长度(字符形式, 中文算一个)

    • blength(s): s的长度(字节形式, 和编码有关)

    • match(String, Ere): String是否匹配Ere 未找到, 返回0

    • split(s, a, fs): 在fs上将s分成序列a, a是一个数组,fs是分隔符,缺省为空格 函数本身返回数组的长度

    • substr(s, p): 返回s从p开始的子串

    • tolower(String) 返回小写String

    • toupper(String)

    • printf(Format, Expr, Expr) 格式化字符串输出

    • print 普通正常输出, 加不加括号都行

        %d %u %f %s %c %p %e %x %o %g  复习C,一模一样 %g 自动选择合适的表示法
        awk 'BEGIN{n0="金价为";n1=124.113;n2="较昨日上涨";n3=-1.224;printf("%s%.2f,%s%g\n", n0, n1, n2, n3);}'
      
  • 控制语句

    • 条件判断

        if(....)
            {....}
        else
            {....}
      
    • 循环

        while(....)
            {....}
            
        for(k in Array)  # 注意k是键值,并不是数组的内容
            {....}
        for(k=0;k<=20;k++)
            {....}
            
        do(....)
        while(条件)
        
        break
        continue
        next ??
        exit 使程序中断直接到END语句块, 如果在END中出现, 则终止脚本
      

内置变量:

  • FS 分隔符,默认空格
  • NR 当前行数,从1开始
  • NF 当前记录字段个数 依次类推 $NF $(NF-1)
  • $0 当前记录 全行
  • $1~$n 当前记录的第n个字段 当前行第几个字段从1开始(注意是字段,以默认FS分割开的)

exp:

cat test | awk '/.*?山$/' 
awk '/^亏/'  test
# 显示匹配hello的行, action默认即为print

# 这个我们可以改写成在模式里面用match函数匹配
awk '{print match($0, /[0-9]+/)?"ok":"no found";}' test
# ?: 符号也是C里面的, /[0-9]+/ 是正则匹配, 输出匹配结果呢?如下, 省略BEGIN语句块
awk '{if(match($0, /山/))print $0}' test


cat hello.txt | awk 'length($0) > 80{parint NR}'
# 打印长度大于80的行数, 注意打印的是行数 print NR行数,如果想打印本身$0
cat hello.txt | awk 'NR==3, NR==5{print $1, $NF}'
# 打印3 ,5 行第一列和最后一列
cat test | awk -F, 'NR==36446{print $1, $NF}'
# 改为中文逗号分割 等同于:
awk -F, 'NR==36446{print $1}' test 
# 或者在BEGIN配置需要的变量,然后pattern选择条件 {command}处理
awk 'BEGIN{FS=","}NR==36446{print $1}' test 
awk 'BEGIN{FS=","}{if(NR==36446)print $1}' test 

其它

  • 输出到一个文件

      awk 'BEGIN{FS=","}length($0)>=20{print $1}' test > test2
      awk 'BEGIN{FS=","}length($0)>=20{print $1 > "test2"}' test
      awk 'BEGIN{FS=","}length($0)>=20{print $1 >> "test2"}' test
      # 这三句效果一样
    
  • 读取外部输入

    • getline

        awk 'BEGIN{"date" | getline out; print out;}' test
        awk 'BEGIN{"date" | getline out; split(out, mon);for(k in mon)print k, mon[k]}'
        awk 'BEGIN{"date" | getline out; lens=split(out, mon);for(k=1;k<=lens;k++)print                         k, mon[k]}'                     
        
        awk 'BEGIN{while("ls" | getline) print}'  
        #用while语句 对ls的输出逐行处理(在正式处理输入前), 如果不用while的话默认是第一行
        awk 'BEGIN{"ls" | getline; print}' 
        
        #用户手动输入
        awk 'BEGIN(print "Enter your name:";getline name; print name)'")}'
      
  • 打开外部文件: 依然是利用管道 + getline来交互

      awk 'BEGIN{while("cat test"|getline out)print $0;close("test")}'
      # 这样子是打不出来的, 管道传递的值都给out了,$0每行都是空
      awk 'BEGIN{while("cat test"|getline out)print out;close("test")}'
      awk 'BEGIN{while("cat test"|getline)print $0;close("test")}'
    
  • 调用外部应用程序 调用shell命令

    • system("....") 调用linux命令, 返回liunx输出结果

        awk 'BEGIN{b=system("ls -al");print b;}'
        # 最后为啥会有个0 ?? 求解释??
        # 或者我们可以利用管道更简单些
        awk 'BEGIN{"date"|getline b; print b}'
      
  • 时间函数

    • mktime(YYYY MM dd HH MM ss[DST]) 生成时间格式

    • strftime([format [, timestamp]])

    • systime() 得到时间戳

        awk 'BEGIN{tstamp=mktime("2001, 01 01 12 12 12");print strftime("%c", tstamp);}'
        # awk version 20070501中没有mktime的函数, 2001年....
      


写了很多,但是常用的应该是BEGIN{}pattern{}END{}来处理常规的文本数据,日期什么的直接shell就好了
更多详细数据格式 http://man.linuxde.net/awk

你可能感兴趣的:(linux-awk)