zoukankan      html  css  js  c++  java
  • awk文本处理工具

    awk

    awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息
    awk处理过程: 依次对每一行进行处理,然后输出
    awk命令形式:
    awk  [-F|-f|-v]   'BEGIN{} //{command1;command2} END{}'   file
    [-F|-f|-v]        大参数,-F指定分隔符,-f调用脚本,-v定义变量 var=value
    '  '                 引用代码块
    BEGIN         初始化代码块,在对每一行进行处理之前,初始化代码,主要是引用全局变量,设置FS分隔符
    //                  匹配代码块,可以是字符串或正则表达式
    {}                  命令代码块,包含一条或多条命令
    ;                多条命令使用分号分隔
    END            结尾代码块,在对所有行进行处理之后再执行的代码块,主要是进行最终计算或输出结尾摘要信息
     
    三种执行方式:
    1.命令行方式
    awk [-F  field-separator]  'commands'  input-file(s)
    其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
    在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
     
    2.shell脚本方式
    将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
    相当于shell脚本首行的:#!/bin/sh
    可以换成:#!/bin/awk
     
    3.将所有的awk命令插入一个单独文件,然后调用:
    awk -f awk-script-file input-file(s)
    其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的。
     
     
    特殊要点:
    $0           表示整个当前行
    $1           每行第一个字段
    NF          所在行的字段数量变量
    NR          每行的记录号,多文件记录递增
    FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始
               制表符
              换行符
    FS          BEGIN时定义分隔符
    RS         输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
    ~            匹配,与==相比不是精确比较
    !~           不匹配,不精确比较
    ==         等于,必须全部相等,精确比较
    !=           不等于,精确比较
    &&      逻辑与
    ||            逻辑或
    +            匹配时表示1个或1个以上
    ^        行首
    $        行尾
    .      除了换行符以外的任意单个字符
    *      前导字符的零个或多个
    .*       所有字符
    []        字符组内的任一字符
    [^]           对字符组内的每个字符取反(不匹配字符组内的每个字符)
    ^[^]    非字符组内的字符开头的行
    [a-z]        小写字母
    [A-Z]     大写字母
    [a-Z]      小写和大写字母
    [0-9]   数字
    <           单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词
    >           单词尾
    OFS       输出字段分隔符, 默认也是空格,可以改为制表符等
    ORS      输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
    -F'[:#/]'   定义三个分隔符
     

    print 是awk打印指定内容的主要命令

    awk '{print}'  /etc/passwd   ==   awk '{print $0}'  /etc/passwd 

    awk '{print " "}' /etc/passwd         //不输出passwd的内容,而是输出相同个数的空行,进一步解释了awk是一行一行处理文本

    awk '{print "a"}'   /etc/passwd      //输出相同个数的a行,一行只有一个a字母

    awk -F":" '{print $1}'  /etc/passwd

    awk -F: '{print $1; print $2}'   /etc/passwd                   //将每一行的前二个字段,分行输出,进一步理解一行一行处理文本

    awk  -F: '{print $1,$3,$6}' OFS=" " /etc/passwd        //输出字段1,3,6,以制表符作为分隔符

    -f指定脚本文件

    awk -f script.awk  file BEGIN{ FS=":" } {print $1}              

    //效果与awk -F":" '{print $1}'相同,只是分隔符使用FS在代码自身中指定

    awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' test                      //BEGIN{X=0}初始化

    I find 4 blank lines.  

    ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}'                    //计算文件大小 total size is 17487

    -F指定分隔符

    $1 指指定分隔符后,第一个字段,$3第三个字段, 是制表符

    一个或多个连续的空格或制表符看做一个定界符,即多个空格看做一个空格

    awk -F":" '{print $1}'  /etc/passwd

    awk -F":" '{print $1 $3}'  /etc/passwd                       //$1与$3相连输出,不分隔

    awk -F":" '{print $1,$3}'  /etc/passwd                       //多了一个逗号,$1与$3使用空格分隔

    awk -F":" '{print $1 " " $3}'  /etc/passwd                  //$1与$3之间手动添加空格分隔

    awk -F":" '{print "Username:" $1 " Uid:" $3 }' /etc/passwd       //自定义输出 

    awk -F: '{print NF}' /etc/passwd                                //显示每行有多少字段

    awk -F: '{print $NF}' /etc/passwd                              //将每行第NF个字段的值打印出来  

    awk -F: 'NF==4 {print }' /etc/passwd                       //显示只有4个字段的行

    awk -F: 'NF>2{print $0}' /etc/passwd                       //显示每行字段数量大于2的行

    awk '{print NR,$0}' /etc/passwd                                //输出每行的行号,使用空格分隔

    awk -F: 'NR==5{print}'  /etc/passwd                         //显示第5行

    awk -F: 'NR==5 || NR==6{print}'  /etc/passwd         //显示第5行和第6行

    route -n|awk 'NR!=1{print}'                                       //不显示第一行 

    //匹配代码块
    //纯字符匹配   !//纯字符不匹配   ~//字段值匹配    !~//字段值不匹配   ~/a1|a2/字段值匹配a1或a2   

    awk '/mysql/' /etc/passwd

    awk '/mysql/{print }' /etc/passwd

    awk '/mysql/{print $0}' /etc/passwd                   //三条指令结果一样

    awk '!/mysql/{print $0}' /etc/passwd                  //输出不匹配mysql的行

    awk '/mysql|mail/{print}' /etc/passwd

    awk '!/mysql|mail/{print}' /etc/passwd

    awk -F: '/mail/,/mysql/{print}' /etc/passwd         //区间匹配

    awk '/[2][7][7]*/{print $0}' /etc/passwd               //匹配包含27为数字开头的行,如27,277,2777...

    awk -F':' '$1~/mail/{print $1}' /etc/passwd           //$1匹配指定内容才显示

    awk -F':' '{if($1~/mail/) print $1}' /etc/passwd     //与上面相同

    awk -F':’ '$1!~/mail/{print $1}' /etc/passwd          //不匹配

    awk -F':' '$1!~/mail|mysql/{print $1}' /etc/passwd       

    IF语句
    必须用在{}中,且比较内容用()扩起来

    awk -F: '{if($1~/mail/) print $1}' /etc/passwd            //简写

    awk -F: '{if($1~/mail/) {print $1}}'  /etc/passwd       //全写

    awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd            //if...else...

    条件表达式

    ==   !=   >   >= 

    awk -F":" '$1=="mysql"{print $3}' /etc/passwd  
    awk -F":" '{if($1=="mysql") print $3}' /etc/passwd          //与上面相同 
    awk -F":" '$1!="mysql"{print $3}' /etc/passwd                 //不等于
    awk -F":" '$3>1000{print $3}' /etc/passwd                      //大于
    awk -F":" '$3>=100{print $3}' /etc/passwd                     //大于等于
    awk -F":" '$3<1{print $3}' /etc/passwd                            //小于
    awk -F":" '$3<=1{print $3}' /etc/passwd                         //小于等于
     
    逻辑运算符
    && || 
    awk -F: '$1~/mail/ && $3>8 {print }' /etc/passwd         //逻辑与,$1匹配mail,并且$3>8
    awk -F: '{if($1~/mail/ && $3>8) print }' /etc/passwd
    awk -F: '$1~/mail/ || $3>1000 {print }' /etc/passwd       //逻辑或
    awk -F: '{if($1~/mail/ || $3>1000) print }' /etc/passwd 
     
    数值运算
    awk -F: '$3 > 100' /etc/passwd    
    awk -F: '$3 > 100 || $3 < 5' /etc/passwd  
    awk -F: '$3+$4 > 200' /etc/passwd
    awk -F: '/mysql|mail/{print $3+10}' /etc/passwd                    //第三个字段加10打印 
    awk -F: '/mysql/{print $3-$4}' /etc/passwd                             //减法
    awk -F: '/mysql/{print $3*$4}' /etc/passwd                             //求乘积
    awk '/MemFree/{print $2/1024}' /proc/meminfo                  //除法
    awk '/MemFree/{print int($2/1024)}' /proc/meminfo           //取整
     
    输出分隔符OFS
    awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS=" " netstat.txt
    awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS=" " netstat.txt     //输出字段6匹配WAIT的行,其中输出每行行号,字段4,5,6,并使用制表符分割字段
     
    输出处理结果到文件
    ①在命令代码块中直接输出    route -n|awk 'NR!=1{print > "./fs"}'   
    ②使用重定向进行输出           route -n|awk 'NR!=1{print}'  > ./fs
     
    格式化输出
    netstat -anp|awk '{printf "%-8s %-8s %-10s ",$1,$2,$3}' 
    printf表示格式输出
    %格式化输出分隔符
    -8长度为8个字符
    s表示字符串类型
    打印每行前三个字段,指定第一个字段输出字符串类型(长度为8),第二个字段输出字符串类型(长度为8),第三个字段输出字符串类型(长度为10)
    netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s ",$1,$2,$3}'
    netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-3s %-10s %-10s %-10s ",NR,$1,$2,$3}'
     
     
    IF语句
    awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd
    small
    small
    small
    large
    small
    small
    awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A," ",B}' /etc/passwd 
    //ID大于100,A加1,否则B加1
    awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示
    另一种形式
    awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd 
    awk -F: '{print ($3>100 ? $3": yes":$3": no")}'  /etc/passwd
     
    while语句
    awk 'BEGIN{  test=100;  total=0;  while(i<=test)  {  total+=i;  i++;  }  print total;  }'
     
     
    数组
    awk 'BEGIN {record="123#456#789";split(record,myarray,"#")} END {for (i in myarray) {print myarray[i]} }
     
    应用1
    awk -F: '{print NF}' helloworld.sh                                                   //输出文件每行有多少字段
    awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh                               //输出前5个字段
    awk -F: '{print $1,$2,$3,$4,$5}' OFS=' ' helloworld.sh                 //输出前5个字段并使用制表符分隔输出
    awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS=' ' helloworld.sh           //制表符分隔输出前5个字段,并打印行号
     
    应用2
    awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段
    awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS=' ' helloworld.sh       //制表符分隔输出多字段
     
    应用3
    awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数
    awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段
     
    应用4
    计算/home目录下,普通文件的大小,使用KB作为单位
    ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}'
    ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思
     
    应用5
    统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少
    netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s ", i," ",sum[i]}'
    LISTEN            25 
    CONNECTED         54
     
    应用6
    统计/home目录下不同用户的普通文件的总数是多少?
    ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s ",i," ",sum[i]}' 
    root           374 
    统计/home目录下不同用户的普通文件的大小总size是多少?
    ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s ",i," ",sum[i]/1024/1024,"MB"}'
     
    应用7
    输出成绩表

    awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total ";printf " "}    

      {math+=$3; eng+=$4; com+=$5;printf "%-8s %-7s %-7s %-7s %-9s %-10s %-7s ",NR,$1,$2,$3,$4,$5,$3+$4+$5}  

      END{printf " ";printf "%-24s %-7s %-9s %-20s ","Total:",math,eng,com;printf "%-24s %-7s %-9s %-20s ","Avg:",math/NR,eng/NR,com/NR}' test0
    [root@localhost home]# cat test0 

    Marry   2143 78 84 77
    Jack    2321 66 78 45
    Tom     2122 48 77 71
    Mike    2537 87 97 95
    Bob     2415 40 57 62
     
    参考资料:
    http://blog.chinaunix.net/uid-23302288-id-3785105.html
    https://zhangge.net/1939.html
     

    补充

    111111111
    222222222
    333333333
    444444444
    555555555
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    999999999
    999999999
    999999999
    999999999
    999999999
    999999999
    999999999
    aaaaaaaaaa
    6666666666
    7777777777
    8888888888
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    9999999999
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa
    aaaaaaaaaa

    cat a.txt |sort|uniq  -c  #sort排序、uniq去重、-c查看去重了多少行

    cut

    d指定分隔符

    f指定取第几部分

    cat a.txt |cut -d: -f1

    cat a.txt |cut -d: -f1,3   取第三部分

    du -sh /boot/ 统计文件大小

    find /boot   -type f  查找/boot目录下的普通文件

    find /boot   -name *.txt  查找/boot目录下的 .txt后缀的文件

    find /boot  -size +30M   查找大于30M的文件

    find /boot  -size +10M -size -30M   查找大于10M小于30M的文件

    grep -rl "root" /test   递归查找/test下包含root的文件名,输出文件名

  • 相关阅读:
    解析XML技术
    XML名命空间
    XML解析器
    java列表组件鼠标双击事件的实现
    XML(可拓展标记语言)基本概念
    数据包式套接字:基于UDP协议的Socket网络编程
    流式套接字:基于TCP协议的Socket网络编程(案例3)
    剑指 Offer 58
    剑指 Offer 58
    剑指 Offer 57
  • 原文地址:https://www.cnblogs.com/domestique/p/6746938.html
Copyright © 2011-2022 走看看