面向记录的文本处理:awk

风行水上 @ 2011-07-15 23:18:34
标签:

    Awk 把文件中的每行看作一条记录,每条记录又可以看作空格分割开来的字段。这很像是面向记录的数据库的格式。

    一个简单的awk程序看起来如下:

    awk '/abc/ {print $2}' file.txt
    

    它表示遇到包含字符串"abc"的行时,输出第二个字段($2)。

    awk 中的特殊变量

    • FS : 字段分隔符
    • RS : 记录分隔符
    • OFS : 输出字段分隔符
    • ORS : 输出记录分隔符
    • NF : 当前记录中的字段数
    • NR : 当前记录数
    • FNR : 当前记录在当前文件中的序号数 (用于同时处理多个文件的时候)
    • FILENAME : 当前文件的名字

    跨行的记录

    通常一条记录就是一行,字段是行中的一部分。利用RS变量,可以实现跨行的记录的操作。

    比如对于文件

    #Name
    #Age
    
    Zhang San
    18
    
    Li Si
    19
    

    可以处理如下:

    BEGIN { RS="\n\n"; FS="\n"; }
    
    # 第一条记录表头,略过不处理
    ! /#/ {
      print $1,$2;
    }
    

    awk中的排序

    固然可以通过管道(Pipe)在awk程序的输出在外部进行排序,在awk内部对数组进行排序后再输出会更自然,尤其是需要对几组不同的数据分别排序的时候。

    asort & asorti

    asortasorti是awk内置的排序函数。前者按值排序,后者按键值排序。

    asorti(data, dest);
    for(i in dest) {
      k = dest[i];
      print k, data[k];
    }
    
    asort(data);
    for(k in data) print k, data[k];
    

    asort有个“缺点”是会破坏原数组的索引。

    PROCINFO["sorted_in"]

    在利用for(k in array)语句输出之前,可以通过设置PROCINFO["sorted_in"]来影响排序顺序。

    • @unsorted
    • indice
      • @ind_num_asc | @ind_num_desc
      • @ind_str_asc | @ind_str_desc
    • value
      • @val_type_asc | @val_type_desc
      • @val_num_asc | @val_num_desc
      • @val_str_asc | @val_str_desc
    • function

    这种方法似乎需要高一点版本的awk程序。

    "| sort" 利用awk中的输出重定向来排序

    for(k in data) print k, data[k] | "sort -n";
    close("sort -n");
    
    # 一个好的实践
    pipe = "sort -n";
    for(k in data) print k, data[k] | pipe;
    close(pipe);
    

    应用实例

    汇总文件

    常用的比如说对某列进行相加汇总:

    awk '{sum+=$3;} END {print sum;}' file.txt
    

    去除文件中的重复行

    如果要去除文件中的重复行,有下面三种情况:

    • 文件已经排序:uniq file.txt
    • 允许重新排序:sort -u file.txt
    • 不允许重排序:awk '!($0 in array) { array[$0]; print }' file.txt

    awk程序代码转换为C程序代码

    awka可以把你的awk程序转换为C程序代码,然后编译成可执行程序。这可以:

    • 增加程序执行速度
    • 保护你的程序代码

    Awka-ELM提供了一个框架,以允许对awk进行扩展。

    标签:

      分享到:
      comments powered by Disqus

      19/21ms