• awk理论详解、实战


    答疑解惑:

    为什么用awk取IP的时候用$4?
    ifconfig eth0 | awk -F '[ :]+' 'NR==2{print $4}'
    IP第二行内容如下:
              inet addr:10.0.0.41  Bcast:10.0.0.255  Mask:255.255.255.0
    
    # 因为分隔符-F的'+',表示将多个空格或冒号当成一个对待,此时大多数人都会认为$1是inet,
    你不是说把多个空格当成一个,那就把前面的空格都去掉就ok么.实际情况是:
    # 分隔符前后必须有内容,你把前面这么多空格当成一个,那它后面有字段,前面没字段,它去分割谁?
    所以:以空格开头的(不管是一个还是多个)行,空格将是第一个字段.
    echo " 1 2 3 4" | awk -F '[: ]+' '{print $1,$2}'
     1
    

    1.基本结构

    awk BEGIN{coms}/pattern/{coms}END{coms}

       开始模块 /找谁/{干什么} 结束模块

    a.BEGIN和END模块最多各出现一次

    b./找谁/{干什么},可以是多个,比如:

    NR==2{print $1}NR==5{print $2}

    2.常用内置变量

    $0:当前记录,一整行;

    $1,$2,$3...$n:第n个字段,字段由FS分隔;

    FS(filed separator):输入字段分隔符,默认是空格;

    OFS:输出字段分隔符,默认为空白字符;

    cat test.txt
    ABC:123:Jack
    DEF:456:Alice
    GHI:789:Amy
    # 使用内置变量时,要使用-v选项来指定对应的变量
    awk -v FS=":" -v OFS="=" '{print $1,$2}' test.txt
    

    NF(number of filed):字段数,有多少字段,$NF代表最后一个字段;

    NR(Number of Record):行号,从1开始;

    FNR:当前输入文件的记录数目.

    # 将/etc/passwd中第一行的第一个元素和第七个元素调换位置
    awk -F ":" 'NR==1{print $7":"$2":"$3":"$4":"$5":"$6":"$1}' /etc/passwd
    # 取出输出内容的第三行的倒数第二列
    df -hT | awk 'NR==3{print $(NF-1)}'
    #取/etc/passwd第10行到20行的第三列,写入到test.txt中
    awk -F ":" 'NR>9 && NR<21{print $3}' /etc/passwd | cat -n
    awk -F ":" 'NR>9 && NR<21{print $3}' /etc/passwd > test.txt  # 用双引号不行
    

    3.不常用内置变量

    RS(Record Separator):输入记录分隔符(输入换行符),默认为换行符;

    ORS(Out Record Separator):输出记录分隔符(输出换行符),指定输出时的换行符;

    FILENAME:当前文件名;

    ARGV:数组,保存的是命令行所给定的各参数;

    ARGC:ARGC数组的个数.

    # 遇见了RS指定的分隔符就换行
    awk  -v RS=":" '{print NR,$0}' test.txt
    # 遇见了换行符就把
    替换成ORS指定的分隔符
    awk  -v ORS="---" '{print $0}' test.txt
    ABC:123:Jack---DEF:456:Alice---GHI:789:Amy---[root@nfs01 ~]#
    
    awk 'BEGIN{print ARGV[0],ARGV[1],ARGV[2],ARGC}' a.txt b.txt
    awk a.txt b.txt 3
    
    # 自定义变量:
    # 使用-v来自定义变量,-v varname=value
    awk -v myVar="testvar" 'BEGIN{print myVar}'
    # 在program中直接定义,定义变量和action之间需要用;隔开
    awk 'BEGIN{myVar="testvar";print myVar}'
    

    4.awk格式化:

    # 先介绍一下printf
    printf "%s
    " abc def ghi jkl
    abc
    def
    ghi
    jkl
    printf "( %s )" 1 18 66;echo""
    ( 1 )( 18 )( 66 )
    a.默认不会换行,如果需要,可以在"格式替换符"后加"
    "进行转义;
    b."替换符"和"被格式化的文本"之间需要用"逗号"隔开;
    c."替换符"和"被格式化的文本"得一一对应.
    awk -v FS=":" 'BEGIN{printf "%-20s	 %s
    " , "User","UID"} {printf "%-20s	 %s
    " , $1,$3}' /etc/passwd
    # "-"表示左对齐,不加默认右对齐
    netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s 
    ",$1,$2,$3}'
    

    5.模式:也就是条件,要找谁

    # 关系运算符模式:
    awk 'NR>3 && NR<6 {print $0}' /etc/passwd
    # 正则模式:awk '/正则表达式/{print xx}' filename
    awk '//bin/bash$/{print $0}' /etc/passwd
    # 当使用{x,y}类型次数匹配的正则表达式时,需要使用--posix选项或--re-interval选项
    awk --posix '/hel{2,3}o/{print $0}' test3
    hello
    helllo
    # 行范围模式:
    # awk '/正则1/,/正则2/{动作}' filename
    # 从被正则1匹配到的行开始,到被正则2匹配到的行结束,之间所有行都会执行对应的动作,
    # 这种模式被称为行范围模式
    # 想要从如下文本中找出,网卡1的地址在192.168.0.0、16网段的主机
    cat test5
    主机名  网卡1的IP        网卡2的IP
    主机A   192.168.1.123    192.168.1.124
    主机B   192.168.2.222    172.16.100.2
    主机C   10.1.0.1         172.16.100.3
    主机D   10.1.5.1         192.168.1.60
    awk '$2~/192.168.[0-9]{1,3}.[0-9]{1,3}/{print $1,$2}' test5
    

    6.控制语句

    # 必须用在{}中,且比较内容用()括起来
    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
    awk -F: 'NR!=1{if($3<500) {print $1,"Suser"} else {print $1,"Nuser"}}' /etc/passwd
    awk 'BEGIN{for(i=1;i<=6;i++){print i}}'
    # while循环是只有满足条件时才执行对应语句;
    awk 'BEGIN{i=1;while(i<=6){print i;i++}}'
    # do...while循环是无论是否满足条件,先执行一遍do对应的代码,
    # 然后再判断是否满足while对应的条件,满足则执行do对应的代码;不满足则不执行.
    awk 'BEGIN{i=1;do{print "hehe";i++}while(i<=5)}'
    

    a.continue和break

    # 注意这条命令中的括号,当i的值为3时,跳过当前循环:
    awk 'BEGIN{for(i=1;i<=5;i++) {if (i==3){continue};print i}}'  
    #当i的值为3时,跳出整个循环:
    awk 'BEGIN{for(i=1;i<=5;i++) {if (i==3){break};print i}}'
    

    b.exit、next

    # 如果没有在END模式使用exit,则直接跳出awk命令:
    awk 'BEGIN{print 1;exit;print 2}'
    # 如果在END模式中使用了exit,则直接执行END,跳过其它动作:
    awk 'BEGIN{print "start";exit}{print $0}END{print "over"}' test5
    # next让awk不对匹配到的行进行操作,直接处理下一行:
    awk '{if (NR==2){next} print $0}' test5
    

    c.条件、逻辑、数值

    # 条件表达式
    awk -F: '$1=="mysql"{print $3}' /etc/passwd
    # 逻辑运算符
    awk -F: '$1~/mail/ && $3>8 {print }' /etc/passwd     # 逻辑与
    awk -F: '$1~/mail/ || $3>1000 {print }' /etc/passwd  # 逻辑或
    # 数值运算
    awk -F: '/root|mail/{print $3+10}' /etc/passwd
    10
    18
    21
    # 这条命令为什么打印了三行,因为下面这条命令会匹配到三行
    awk -F: '/root|mail/' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    

    7.实际应用

    应用1:
    # 计算/etc目录下,普通文件的大小,使用KB作为单位
    ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'
    应用2:
    # 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少?
    netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s 
    ", i," ",sum[i]}'
    应用3:
    # 统计/etc目录下不同用户的普通文件的总数是多少?
    ls -l|awk 'NR!=1 && !/^d/{sum[$3]++}END{for (i in sum) printf "%-6s %-5s %-3s 
    ",i," ",sum[i]}'
    # 统计/etc目录下不同用户的普通文件的大小总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"}'
    应用4:
    # ftp|http|mysql的端口号是多少
    awk -F "[ /]+" '$1~/^(ftp|http|mysql)$/{print $1,$2}' /etc/services | uniq
    # ^http$:前后都加上,表示只查找指定内容,其实不加也行
    # 计算/etc/services文件中的空行
    grep -c "^$" /etc/services
    awk '/^$/{a=a+1;print a}END{print a}' /etc/services
    awk '/^$/{a=a+1}END{print a}' /etc/services
    应用5:
    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
    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
    
    Lineno.   Name    No.    Math   English   Computer    Total
    ------------------------------------------------------------
    1        Marry   2143    78      84        77         239     
    2        Jack    2321    66      78        45         189     
    3        Tom     2122    48      77        71         196     
    4        Mike    2537    87      97        95         279     
    5        Bob     2415    40      57        62         159     
    ------------------------------------------------------------
    Total:                   319     393       350                  
    Avg:                     63.8    78.6      70
    

    参考linux awk详解:https://www.cnblogs.com/xudong-bupt/p/3721210.html

  • 相关阅读:
    ThreadLocal用法
    Spring Cloud Alibaba 使用RestTemplate进行服务消费
    Spring Cloud Alibaba 使用Nacos作为配置管理中心
    Spring Cloud Alibaba 使用Nacos作为服务注册中心
    Spring Cloud Alibaba 介绍及工程准备
    Redission 支持GsonCodec
    Maven Archetype快速构建项目
    拜占庭将军问题
    Paxos算法详解
    Paxos、Raft分布式一致性算法应用场景(转载)
  • 原文地址:https://www.cnblogs.com/fawaikuangtu123/p/10021422.html
Copyright © 2020-2023  润新知