美文网首页
三剑客_awk

三剑客_awk

作者: 慕知 | 来源:发表于2021-01-11 15:48 被阅读0次

    awk,命名于三大作者的名字首字母,也是一门编程语言,这里介绍的是文本处理工具

    一,awk原理

    
    [root@m01~]# head -10 /etc/passwd | awk -F: 'BEGIN{count=0}{print$0,count++}END{print count}'
    root:x:0:0:root:/root:/bin/bash 0
    bin:x:1:1:bin:/bin:/sbin/nologin 1
    daemon:x:2:2:daemon:/sbin:/sbin/nologin 2
    adm:x:3:4:adm:/var/adm:/sbin/nologin 3
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 4
    sync:x:5:0:sync:/sbin:/bin/sync 5
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 6
    halt:x:7:0:halt:/sbin:/sbin/halt 7
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin 8
    operator:x:11:0:operator:/root:/sbin/nologin 9
    10
    
    等同于
    [root@m01~]# head -10 /etc/passwd > awk.txt
    [root@m01~]# awk 'BEGIN{count=0;FS=":"}{print $o,count++}END{print count}' awk.txt
    
    
    awk -F: 'BEGIN{count=0}{print$0,count++}END{print count}'
    
    BEGIN{count=0}      行前处理
    {print$0,count++}   行处理
    END{print count}    行后处理
    
    
    
    
    运行原理:
    1,先运行 行前处理 BEGIN{count=0}
    2,再运行 行处理
    - 读一行到内存中,然后awk 生成一堆内置变量
         &0 : 一整行内容
         &1 : 以指定分隔符隔开的第一段内容
         &0 : 以指定分隔符隔开的第二段内容
    
       NR   行号
       NF   列,即段
       FS   行的分隔符 FS=" ",把输入的内容以空格为分隔符
       OFS  以...为分隔符   例OFS=":" ,把输出的内容以:为分隔符
    
    
    - 运行行处理代码
    
    - 循环往复  直到所有行被处理
    
    3,最后运行 行后处理
    
    
    
    
    
    
    # 取出最后一行
    [root@m01~]# awk 'BEGIN{count=0;FS=":"}{print $NF}' awk.txt
    /bin/bash
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin
    /bin/sync
    /sbin/shutdown
    /sbin/halt
    /sbin/nologin
    /sbin/nologin
    
    
    # 标记行号
    [root@m01~]# awk -F: '{print NR,$0}' awk.txt
    1 root:x:0:0:root:/root:/bin/bash
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    6 sync:x:5:0:sync:/sbin:/bin/sync
    7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    8 halt:x:7:0:halt:/sbin:/sbin/halt
    9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10 operator:x:11:0:operator:/root:/sbin/nologin
    
    
    #取出第一列和第三列,以-为分隔符
    [root@m01~]# awk 'BEGIN{count=0;FS=":";OFS="-"}{print $1,$3}' awk.txt
    root-0
    bin-1
    daemon-2
    adm-3
    lp-4
    sync-5
    shutdown-6
    halt-7
    mail-8
    operator-11
    # 以空格为分隔符,直接逗号隔开即可;如下
    [root@m01~]# awk -F: 'BEGIN{count=0}{print $1,$3;count++}END{print count}' awk.txt
    
    
    
    
    #取出第一行和倒数第二行
    [root@m01~]# awk -F: '{print $1,$(NF-1)}' awk.txt
    root /root
    bin /bin
    daemon /sbin
    adm /var/adm
    lp /var/spool/lpd
    sync /sbin
    shutdown /sbin
    halt /sbin
    mail /var/spool/mail
    operator /root
    # 注意 使用NF倒着数,一定要加上括号  
     $(NF-1)  倒数第一段
     $(NF-2)  倒数第二段
    
    
    
    
    #可以把行处理放在一个文件中
    [root@m01~]# cat a.awk
    {print $1,$NF}
    
    
    [root@m01~]# awk -F: -f a.awk awk.txt
    root /bin/bash
    bin /sbin/nologin
    daemon /sbin/nologin
    adm /sbin/nologin
    lp /sbin/nologin
    sync /bin/sync
    shutdown /sbin/shutdown
    halt /sbin/halt
    mail /sbin/nologin
    operator /sbin/nologin
    # 注意 这时候不需要再加 引号
    
    

    二,模式匹配

    1,行定位
    # 打印出所有行的第一列
    [root@m01~]# awk -F: '{print NR,$1}' awk.txt
    1 root
    2 bin
    3 daemon
    4 adm
    5 lp
    6 sync
    7 shutdown
    8 halt
    9 mail
    10 operator
    
    
    
    
    
    # 打印第三行的第一列
    [root@m01~]# awk -F: 'NR == 3{print $1}' awk.txt
    daemon
    
    
    
    # 取出 第一行到第三行的第一列和最后一列
    [root@m01~]# awk -F: 'NF >=1 && NR <=3{print $1,$NF}' awk.txt
    root /bin/bash
    bin /sbin/nologin
    daemon /sbin/nologin
    
    
    
    #   取出第一行和第三行的 第一列和第三列
    [root@m01~]# awk -F: 'NR == 1 || NR == 3{print $1,$3}' awk.txt
    root 0
    daemon 2
    
    
    #  打印出包含root的行
    [root@m01~]# awk -F: '/root/{print NR,$0}' awk.txt
    1 root:x:0:0:root:/root:/bin/bash
    10 operator:x:11:0:operator:/root:/sbin/nologin
    
    
    
    # 打印出 第一列中包含root的行
    [root@m01~]# awk -F: '$1 ~ /root/{print NR,$0}' awk.txt
    1 root:x:0:0:root:/root:/bin/bash
    
    
    # 打印出用户名(即第一列)中不以root开头的行
    [root@m01~]# awk -F: '$1 !~ /root/{print NR,$0}' awk.txt
    
    等同于
    
    [root@m01~]# awk -F: '!($1 ~ /^root/){print NR,$0}' awk.txt
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    ... ...
    # 注意感叹号前需要用上小括号 () 
    
    
    
    
    
    
    #  打印出不是大于等于第二行的内容,即第一行
    [root@m01~]# awk -F: '! (NR>=2){print NR,$0}' awk.txt
    1 root:x:0:0:root:/root:/bin/bash
    
    
    
    
    # 取出 从zx   到xy的行
    [root@m01~]# cat a.txt
    1111zx
    2345
    xy
    23
    345
    zx
    1213
    123xy
    
    [root@m01~]# awk -F: '/zx/,/xy/{print NR,$0}' a.txt
    1 1111zx
    2 2345
    3 xy
    6 zx
    7 1213
    8 123xy
    #  注意会有两段内容,从匹配zx开始,到xy结束为一段
    
    
    
    
    
    # 如上,如果第二段没有xy作为结束,会一直吃到结尾
    [root@m01~]# cat a.txt
    1111zx
    2345
    xy
    23
    345
    zx
    1213
    
    [root@m01~]# awk -F: '/zx/,/xy/{print NR,$0}' a.txt
    1 1111zx
    2 2345
    3 xy
    6 zx
    7 1213
    
    
    
    
    #  取出2-4行中包含xy的内容
    [root@m01~]# awk -F: 'NR >=2 && NR <= 4 && /xy/{print NR,$0}' a.txt
    3 xy
    
    2.算数运算
    如下的意思:姓名zx的月薪是12000 ,年龄18岁,取出年薪超过10w的人
    [root@m01~]# cat b.txt
    zx:12000:18
    egon:21000:38
    lil:3000:19
    
    [root@m01~]# awk -F: '$2*12 > 100000{print $1}' b.txt
    zx
    egon
    
    
    
    
    
    # 打印文件中的偶数行
    [root@m01~]# awk -F: 'NR % 2 == 0{print NR,$0}' awk.txt
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    6 sync:x:5:0:sync:/sbin:/bin/sync
    8 halt:x:7:0:halt:/sbin:/sbin/halt
    10 operator:x:11:0:operator:/root:/sbin/nologin
    
    
    
    # 打印文件中的偶数行的用户
    [root@m01~]# awk -F: 'NR % 2 == 0{print NR,$1}' awk.txt
    2 bin
    4 adm
    6 sync
    8 halt
    10 operator
    
    
    
    
    # 打印文件中的基数行
    [root@m01~]# awk -F: 'NR % 2 !=0{print NR,$0}' awk.txt
    1 root:x:0:0:root:/root:/bin/bash
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    
    等同于
    
    [root@m01~]# awk -F: 'NR % 2 ==1{print NR,$0}' awk.txt
    
    
    % 取余数
    
    3,
    
    # 取出第一列,并标注行号
    1~]# awk -F: 'BEGIN{OFS="---"}{print "行号",NR,"用户名",$1}' awk.txt
    行号---1---用户名---root
    行号---2---用户名---bin
    行号---3---用户名---daemon
    行号---4---用户名---adm
    行号---5---用户名---lp
    行号---6---用户名---sync
    行号---7---用户名---shutdown
    行号---8---用户名---halt
    行号---9---用户名---mail
    行号---10---用户名---operator
    ... ...
    
    
    
    
    为方便看的清晰,可以调整
    方式一:
    [root@m01~]# awk -F: 'BEGIN{OFS="---"}{print "行号"NR,"用户名"$1}' awk.txt
    行号1---用户名root
    行号2---用户名bin
    行号3---用户名daemon
    行号4---用户名adm
    行号5---用户名lp
    行号6---用户名sync
    行号7---用户名shutdown
    行号8---用户名halt
    行号9---用户名mail
    行号10---用户名operator
    
    
    方式二:
    [root@m01~]# awk -F: '{printf "行号:%s---用户名:%s\n",NR,$1}' awk.txt
    行号:1---用户名:root
    行号:2---用户名:bin
    行号:3---用户名:daemon
    行号:4---用户名:adm
    行号:5---用户名:lp
    行号:6---用户名:sync
    行号:7---用户名:shutdown
    行号:8---用户名:halt
    行号:9---用户名:mail
    行号:10---用户名:operator
    
    # 注意,printf ; \n 换行符
    
    4,awk 之 if 判断
    # 算出管理员用户数为 系统用户数为  普通用户数为各为多少(了解即可)
    [root@m01~]# awk -F: 'BEGIN{x=0;y=0;z=0}{if ($3==0){x++} else if ($3>=3 && $3<=999){y++} else {z++}}END{printf "管理员用户数为:%s 系统用户数为:%s 普通用户数为:%s\n",x,y,z}' /etc/passwd
    管理员用户数为:1 系统用户数为:23 普通用户数为:3
    
    
    
    x 代表管理员账户数;y 代表系统用户数;z 代表普通用户数
    
    
    
    shell脚本
    [root@m01~]# cat test.sh
    #!/bin/bash
    x=0
    y=0
    z=0
    for uid in $(awk -F: '{print $3}' /etc/passwd)
    do
        if [ $uid -eq 0 ];then
            let x++
        elif [ $uid -ge 1 -a $uid -le 999 ];then
            let y++
        else
            let z++
        fi
    done
    printf "管理员数为:%s 系统用户数为:%s 普通用户数为:%s\n" $x $y $z
    
    
    
    [root@m01~]# ./test.sh
    管理员数为:1 系统用户数为:25 普通用户数为:1
    
    # 注意:
    shell脚本里需要用$ q取值并中间用空格隔开;$x $y $z
    
    5,awk 之 while循环
    # 循环三次
    方式一:
    [root@m01~]# cat test.txt
    1234abc
    5678qqq
    3456
    pppp
    
    [root@m01~]# awk '{n=1;while (n<=3){print $0;n++}}' test.txt
    1234abc
    1234abc
    1234abc
    5678qqq
    5678qqq
    5678qqq
    3456
    3456
    3456
    pppp
    pppp
    pppp
    
    
    
    方式二:
    [root@m01~]# awk '{for (n=1;n<=3;n++){print $0}}' test.txt
    1234abc
    1234abc
    1234abc
    ... ...
    
    5,awk 之 数组功能
    # 所有的用户名 存到数组里(了解即可)
    方式一:
    [root@m01~]# awk -F: 'BEGIN{i=0}{username[i]=$1;i++}END{for (x=0;x<i;x++){print username[x]}}' /etc/passwd
    root
    bin
    daemon
    adm
    lp
    sync
    shutdown
    halt
    mail
    ... ...
    
    
    
    方式二:
    [root@m01~]# awk -F: 'BEGIN{i=0}{username[i]=$1;i++}END{for (x in username) {print username[x]}}' /etc/passwd
    
    

    练习题补充

    # 打印出用户名字符为4个字符的
    [root@m01~]# awk -F: '$1 ~ /^....$/{print $0}' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    sync:x:5:0:sync:/sbin:/bin/sync
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    
    

    相关文章

      网友评论

          本文标题:三剑客_awk

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