• Linux学习(二十五)正则表达式(三)awk


    awk和sed一样是流式编辑器,它也是针对文档中的行来操作的,一行一行的去执行。awk比sed更加强大,它能做到sed能做到的,同样也能做到sed不能做到的。awk工具其实是很复杂的,但是学那么复杂没有必要,只要能处理日常管理工作中的问题即可。

    1.截取文档中的某个段

    [root@localhost ~]# head -n2 /etc/passwd |awk -F ':' '{print $1}'
    root
    bin

    解释一下,-F 选项的作用是指定分隔符,如果不加-F指定,则以空格或者tab为分隔符。 Print为打印的动作,用来打印出某个字段。$1为第一个字段,$2为第二个字段,依次类推,有一个特殊的那就是$0,它表示整行。

    [root@localhost ~]# head -n2 test.txt |awk -F':' '{print $0}'
    rto:x:0:0:/rto:/bin/bash
    operator:x:11:0:operator:/roto:/sbin/nologin

    注意awk的格式,-F后紧跟单引号,然后里面为分隔符,print的动作要用 { } 括起来,否则会报错。print还可以打印自定义的内容,但是自定义的内容要用双引号括起来。

    [root@localhost ~]# head -n2 test.txt |awk -F':' '{print $1"#"$2"#"$3"#"$4}'
    rto#x#0#0
    operator#x#11#0

    2.匹配字符或者字符串

    [root@localhost ~]# awk '/oo/' test.txt
    operator:x:11:0:operator:/rooto:/sbin/nologin
    roooto:x:0:0:/rooooto:/bin/bash

    跟sed很类似吧,不过还有比sed更强大的匹配。

    [root@localhost ~]# awk -F ':' '$1 ~/oo/' test.txt
    roooto:x:0:0:/rooooto:/bin/bash

    可以让某个段去匹配,这里的’~’就是匹配的意思,继续往下看

    [root@localhost ~]# awk -F ':' '/root/ {print $1,$3} /test/ {print $1,$3}' /etc/passwd
    root 0
    operator 11
    test 511
    test1 512

    awk还可以多次匹配,如上例中匹配完root,再匹配test,它还可以只打印所匹配的段。

    3.条件操作符

    [root@localhost ~]# awk -F ':' '$1=="root"' /etc/passwd
    root:x:0:0:root:/root:/bin/bash

    awk中是可以用逻辑符号判断的,比如 ‘==’ 就是等于,也可以理解为 ‘精确匹配’ 另外也有 >, ‘>=, ‘<, ‘<=, ‘!= 等等,值得注意的是,在和数字比较时,若把比较的数字用双引号引起来后,那么awk不会认为是数字,而认为是字符,不加双引号则认为是数字。

    [root@localhost ~]# awk -F ':' '$3>="500"' /etc/passwd
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
    haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    tcpdump:x:72:72::/:/sbin/nologin
    user11:x:510:502:user11,user11's office,12345678,123456789:/home/user11:/sbin/nologin
    test:x:511:511::/home/test:/bin/bash
    test1:x:512:511::/home/test1:/bin/bash

    在上面的例子中,阿铭本想把uid大于等于500的行打印出,但是结果并不是我们的预期,这是因为awk把所有的数字当作字符来对待了,就跟上一章中提到的 sort 排序原理一样。

    [root@localhost ~]# awk -F ':' '$7!="/sbin/nologin"' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    test:x:511:511::/home/test:/bin/bash
    test1:x:512:511::/home/test1:/bin/bash

    != 为不匹配,除了针对某一个段的字符进行逻辑比较外,还可以两个段之间进行逻辑比较。

    [root@localhost ~]# awk -F ':' '$3<$4' /etc/passwd
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
    games:x:12:100:games:/usr/games:/sbin/nologin
    gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

    另外还可以使用 && 和 || 表示 “并且” 和 “或者” 的意思。

    [root@localhost ~]# awk -F ':' '$3>"5" && $3<"7"' /etc/passwd
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
    haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
    user11:x:510:502:user11,user11's office,12345678,123456789:/home/user11:/sbin/nologin
    test:x:511:511::/home/test:/bin/bash
    test1:x:512:511::/home/test1:/bin/bash

    也可以是或者

    [root@localhost ~]# awk -F ':' '$3>"5" || $7=="/bin/bash"' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin
    haldaemon:x:68:68:HAL daemon:/:/sbin/nologin
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    tcpdump:x:72:72::/:/sbin/nologin
    user11:x:510:502:user11,user11's office,12345678,123456789:/home/user11:/sbin/nologin
    test:x:511:511::/home/test:/bin/bash
    test1:x:512:511::/home/test1:/bin/bash

    4.awk的内置变量

    awk常用的变量有:

    NF :用分隔符分隔后一共有多少段

    NR :行数

    [root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print NF}'
    7
    7
    7
    [root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print $NF}'
    /bin/bash
    /sbin/nologin
    /sbin/nologin

    NF 是多少段,而$NF是最后一段的值, 而NR则是行号。

    [root@localhost ~]# head -n3 /etc/passwd | awk -F ':' '{print NR}'
    1
    2
    3

    我们可以使用行号作为判断条件:

    [root@localhost ~]# awk 'NR>20' /etc/passwd
    postfix:x:89:89::/var/spool/postfix:/sbin/nologin
    abrt:x:173:173::/etc/abrt:/sbin/nologin
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    tcpdump:x:72:72::/:/sbin/nologin
    user11:x:510:502:user11,user11's office,12345678,123456789:/home/user11:/sbin/nologin
    test:x:511:511::/home/test:/bin/bash
    test1:x:512:511::/home/test1:/bin/bash

    也可以配合段匹配一起使用:

    [root@localhost ~]# awk -F ':' 'NR>20 && $1 ~ /ssh/' /etc/passwd
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin

    5.awk中的数学运算

    awk可以把段值更改:

    [root@localhost ~]# head -n 3 /etc/passwd |awk -F ':' '$1="root"'
    root x 0 0 root /root /bin/bash
    root x 1 1 bin /bin /sbin/nologin
    root x 2 2 daemon /sbin /sbin/nologin

    awk还可以对各个段的值进行数学运算:

    [root@localhost ~]# head -n2 /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    [root@localhost ~]# head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4}'
    [root@localhost ~]# head -n2 /etc/passwd |awk -F ':' '{$7=$3+$4; print $0}'
    root x 0 0 root /root 0
    bin x 1 1 bin /bin 2

    当然还可以计算某个段的总和

    [root@localhost ~]# awk -F ':' '{(tot=tot+$3)}; END {print tot}' /etc/passwd
    2891

    这里的END要注意一下,表示所有的行都已经执行,这是awk特有的语法,其实awk连同sed都可以写成一个脚本文件,而且有他们特有的语法,在awk中使用if判断、for循环都是可以的,只是阿铭认为日常管理工作中没有必要使用那么复杂的语句而已。

    [root@localhost ~]# awk -F ':' '{if ($1=="root") print $0}' /etc/passwd
    root:x:0:0:root:/root:/bin/bash

    习题

    1. 用awk 打印整个test.txt (以下操作都是用awk工具实现,针对test.txt)
    2. 查找所有包含 ‘bash’ 的行
    3. 用 ‘:’ 作为分隔符,查找第三段等于0的行
    4. 用 ‘:’ 作为分隔符,查找第一段为 ‘root’ 的行,并把该段的 ‘root’ 换成 ‘toor’ (可以连同sed一起使用)
    5. 用 ‘:’ 作为分隔符,打印最后一段
    6. 打印行数大于20的所有行
    7. 用 ‘:’ 作为分隔符,打印所有第三段小于第四段的行
    8. 用 ‘:’ 作为分隔符,打印第一段以及最后一段,并且中间用 ‘@’ 连接 (例如,第一行应该是这样的形式 'root@/bin/bash‘ )
    9. 用 ‘:’ 作为分隔符,把整个文档的第四段相加,求和

    awk习题答案

    1. awk '{print $0}' test.txt
    2. awk '/bash/' test.txt
    3. awk -F':' '$3=="0"' test.txt
    4. awk -F':' '$1=="root"' test.txt |sed 's/root/toor/'
    5. awk -F':' '{print $NF}' test.txt
    6. awk -F':' 'NR>20' test.txt
    7. awk -F':' '$3<$4' test.txt
    8. awk -F':' '{print $1"@"$NF}' test.txt
    9. awk -F':' '{(sum+=$4)}; END {print sum}' test.txt
    坚持!
  • 相关阅读:
    Eclipse里编辑代码,进度条出现“Remote System Explorer Operation”解决方法
    Fiddler快速入门
    十分钟学会 Fiddler
    网络抓包工具 wireshark 入门教程
    wireshark使用教程
    Apple iOS MDM开发流程
    input file 文件上传,js控制上传文件的大小和格式
    读取注册表获取Windows系统XP/7/8/10类型(使用wcscmp比较wchar[]内容)
    QT 序列化/串行化/对象持久化
    VC 使用msxml6.dll动态链接库中的函数读写XML文件
  • 原文地址:https://www.cnblogs.com/doubilaile/p/7883278.html
Copyright © 2020-2023  润新知