zoukankan      html  css  js  c++  java
  • awk简介

    本质:

    是一门编程语言,有自己的语法和库函数。

    工作机理:

    • 读取每一行

    • 按分隔符把这一行切成多个(不指定分隔符的话,空白或者连续空白就是分隔符)

      $1:代表第一列;$2:第二列。。。。

      $0:整行内容

    • 按需,按特定格式打印出来

    功能:

    • 可以限定处理哪些行
    • 可以根据列的内容做条件分支处理
    • 可以循环所有列
    • 可以自己定义变量

    命令基本用法:

    awk [option] 'PROGRAM' FILE...

    PROGRAME:PATERN{ACTION STATEMENTS}

    例子1:/etc/fstab文件用空白分隔,打印出第二列和第四列。

    列之间用逗号分隔,打印出来的列之间就有空格;不加逗号,就把这2列连一起了

    [root@localhost ~]# tail -4 /etc/fstab
    /dev/mapper/centos-root /                       xfs     defaults        0 0
    UUID=3d3b316a-529e-484a-9895-e785fdde5365 /boot                   xfs     defaul
    /dev/mapper/centos-home /home                   xfs     defaults        0 0
    /dev/mapper/centos-swap swap                    swap    defaults        0 0
    [root@localhost ~]# tail -4 /etc/fstab | awk '{print $2,$4}'
    / defaults
    /boot defaults
    /home defaults
    swap defaults
    [root@localhost ~]# tail -4 /etc/fstab | awk '{print $2 $4}'
    /defaults
    /bootdefaults
    /homedefaults
    swapdefaults
    

    例子2:/etc/fstab文件用空白分隔,打印出第二列和第四列,并随意加几列

    # tail -4 /etc/fstab | awk '{print "hi",$2,$4,567}'
    hi / defaults 567
    hi /boot defaults 567
    hi /home defaults 567
    hi swap defaults 567
    

    由上面2个小例子,可以看出awk的基本使用要点:

    • print的项目间,加了逗号,打印出来的项目之间就有空格
    • print后面的内容,可以是列号,自己定义的变量,随意的字符串和数字
    • print后面如果省略项目,就是打印$0

    选项

    • -F:告诉awk用什么分隔符,去分隔输入
    • -v:自定义变量。var=value。定义多个变量要使用多次-v

    awk的变量

    1,内置变量

    • FS:input file seperator 输入列分隔符,默认是空白或者连续空白

      # tail -4 /etc/fstab | awk -v OFS=',' '{print $3,$4}'
      xfs,defaults
      xfs,defaults
      xfs,defaults
      swap,defaults
      
    • OFS:output file seperator 输出列分隔符,默认是空白或者连续空白

      # tail -4 /etc/passwd | awk -v FS=':' '{print $1,$4}'
      us3 1002
      user100 1003
      user101 1004
      apache 48
      
    # tail -4 /etc/passwd | awk -v FS=':' -v OFS=':' '{print $1,$4}'
    us3:1002
    user100:1003
    user101:1004
    apache:48
    
    • RS:input record seperator 输入行识别符,默认是回车

    • ORS:output record seperator 输出行识别符,默认是回车

    • NF:每行里列的数量

      在awk内部引用变量不需要加$。

      # awk '{print NF}' /etc/fstab
      0
      1
      2
      10
      1
      9
      12
      1
      6
      6
      6
      6
      
    • NR:文件的行号

      # awk '{print NR}' /etc/fstab
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      

      如果是多个文件,则连续计数行号。

      # awk '{print NR}' /etc/fstab /etc/issue
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      
    • FNR:如果是多个文件,则单独计数行号。

      # awk '{print FNR}' /etc/fstab /etc/issue
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      1
      2
      3
      
    • FILENAME:显示文件名

      # awk '{print FILENAME}' /etc/fstab /etc/issue
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/fstab
      /etc/issue
      /etc/issue
      /etc/issue
      
    • ARGC:命令行参数的个数

    • ARGV:数组,保存的是接收到的命令行参数。

      # awk '{print ARGC, ARGV[0],ARGV[1],ARGV[2]}' /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      # awk 'BEGIN{print ARGC, ARGV[0],ARGV[1],ARGV[2]}' /etc/fstab /etc/issue
      3 awk /etc/fstab /etc/issue
      

    2,自定义变量

    变量名区分大小写,可以使用-v定义;也可以在PROGRAM体里定义。什么是PROGRAM,在大括号里的部分。PROGRAME里的多个语句,使用分号分隔。

    • 使用-v定义变量

      # awk -v var="122dd" '{print var}' /etc/issue
      122dd
      122dd
      122dd
      
    • 在在PROGRAM体里定义变量

      # awk '{var="11d";print var}' /etc/issue
      11d
      11d
      11d
      
      

    printf语句用法

    实现格式化输出。不自动换行,使用 是换行。

    格式符:

    • %c:显示ascii码
    • %d,%i:显示十进制整数
    • %e, %E:显示科学计数法
    • %f:显示浮点数
    • %g, %G:显示科学计数法或浮点数
    • %s:显示字符串
    • %u:显示无符号整数
    • %%:显示%自身
    # awk -F: '{printf "username:%s,uid:%d
    ",$1,$3}' /etc/passwd
    username:avahi,uid:70
    username:postfix,uid:89
    

    修饰符:

    • 数字1[.数字2]
    • -数字1[.数字2]:左对齐
    • +数字1[.数字2]:显示数字的符号,正数显示+,符号显示-

    数字1:显示时,列所占用的宽度。默认是右对齐,-号是左对齐。

    数字2:有小数点的话,指定显示几位小数。

    # awk -F: '{printf "username:%15s,uid:%d
    ",$1,$3}' /etc/passwd
    username:        user101,uid:1004
    username:         apache,uid:48
    # awk -F: '{printf "username:%-15s,uid:%d
    ",$1,$3}' /etc/passwd
    username:user100        ,uid:1003
    username:user101        ,uid:1004
    username:apache         ,uid:48
    

    操作符

    1,算术操作符

    a+b,a-b,a*b,a/b,a^b,a%b,

    2,字符串操作符

    没有操作符,就是连接字符串

    3,赋值操作符

    =,+=,-=,*=,/=,%=,^=

    ++,--

    4,比较操作符

    >,>=,<,<=,!=,==

    5,模式匹配符

    ~:左侧的字符串是否能被右侧的模式所匹配

    !~:左侧的字符串是否能被右侧的模式所不匹配

    6,逻辑操作符

    &&,||,!

    7,函数调用

    function_name(arg1,arg2...)

    8,条件表达式

    selector?true:false

    例子:uid大于等于1000的是aa。

    # awk -F: '{$3>=1000?ut="aa":ut="bb"; printf "%s:%d
    ", ut, $3}'
     /etc/passwd
    
    

    PATTERN

    选择要处理的行,不写pattern默认是处理所有行。

    1,/正则表达式/:仅把被匹配到的行作为处理对象

    仅处理UUID开头的行

    # awk -F' ' '/^UUID/{print $1, $3}'
     /etc/fstab
    UUID=3d3b316a-529e-484a-9895-e785fdde5365 xfs
    

    a仅处理不以UUID开头的行

    # awk -F' ' '!/^UUID/{print $1, $3}'
     /etc/fstab
    
    #
    #
    # by
    #
    # filesystems,
    # man
    #
    /dev/mapper/centos-root xfs
    /dev/mapper/centos-home xfs
    /dev/mapper/centos-swap swap
    

    2,关系表达式:结果为真的行,才是处理对象。结果是非0或非空白都是真。

    处理uid大于等于1000的行

    # awk -F: '$3>=1000{print $1,$3}' /etc/passwd
    nfsnobody 65534
    us1 1001
    us3 1002
    user100 1003
    user101 1004
    

    处理shell是bash的行

    最后一列的字符串包含bash的行
    # awk -F: '$NF~"bash"{print $1,$NF}' /etc/passwd
    root /bin/bash
    ys /bin/bash
    us1 /bin/bash
    us3 /bin/bash
    user100 /bin/bash
    user101 /bin/bash
    最后一列的字符串以bash结尾的行
    # awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd
    root /bin/bash
    ys /bin/bash
    us1 /bin/bash
    us3 /bin/bash
    user100 /bin/bash
    user101 /bin/bash
    
    # awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
    root /bin/bash
    ys /bin/bash
    us1 /bin/bash
    us3 /bin/bash
    user100 /bin/bash
    user101 /bin/bash
    
    

    指定处理的行号

    # awk -F: 'NR>=1&&NR<=3{print $1,$NF}' /etc/passwd
    root /bin/bash
    bin /sbin/nologin
    daemon /sbin/nologin
    

    指定处理的开始行,终了行,但不是用数字,而是用pattern

    # awk -F: '/^root/,/^daemon/{print $1,$NF}' /etc/passwd
    root /bin/bash
    bin /sbin/nologin
    daemon /sbin/nologin
    

    3,BEGIN,END

    • BEGIN:处理第一行前,执行一次BEGIN。一般用于打印表头。
    • END:处理完最后一行后,执行一次END。一般用于打印汇总。
    # awk -F: 'BEGIN{print "    username      uid"} {print $1,$3}' /etc/passwd
        username      uid
    root 0
    bin 1
    daemon 2
    

    打印出前5行的username和uid,并在结尾统计出:uid之和

    # awk -F: -v sum=0 'BEGIN{print "username  uid"} NR>=1&&NR<=5{printf "%8s  %3d
    ", $1,$3;sum+=$3} END{printf "       sum:%s
    ",sum}' /etc/passwd
    username  uid
        root    0
         bin    1
      daemon    2
         adm    3
          lp    4
           sum:10
    

    常用的action

    1,控制语句

    • if(condition) {...}

      仅显示uid大于等于1000的行。

      # awk -F: '{ if($3>=1000) {print $1,$3}}' /etc/passwd
      nfsnobody 65534
      ys 1000
      us1 1001
      us3 1002
      user100 1003
      user101 1004
      
    • if(condition) {...} else {...}

      # awk -F: '{ if($3>=1000) {printf "user:%s
      ",$1} else {printf "suser:%s
      ",$1} }' /etc/passwd
      suser:root
      user:nfsnobody
      

      例子:统计磁盘使用量超过10%的分区。

      按空格分隔,用第五列做判断,第五列是Use%,17%,0%等,可以直接和10作比较。

      其实原理是字符串比较,字母的ASCII码大于数字,所以第一行也显示出来了,完美实现要求。

      # df -h
      Filesystem               Size  Used Avail Use% Mounted on
      /dev/mapper/centos-root   38G  6.1G   31G  17% /
      devtmpfs                 1.9G     0  1.9G   0% /dev
      tmpfs                    1.9G     0  1.9G   0% /dev/shm
      tmpfs                    1.9G  9.0M  1.9G   1% /run
      tmpfs                    1.9G     0  1.9G   0% /sys/fs/cgroup
      /dev/sda1               1014M  179M  836M  18% /boot
      /dev/mapper/centos-home   19G   40M   19G   1% /home
      tmpfs                    379M     0  379M   0% /run/user/0
      
      # df -h | awk '{if($5>"10") print $0}'
      Filesystem               Size  Used Avail Use% Mounted on
      /dev/mapper/centos-root   38G  6.1G   31G  17% /
      /dev/sda1               1014M  179M  836M  18% /boot
      
    • switch(expression){case val1 or /pattern/: 语句; case val1 or /pattern/ 语句; ... default: 语句}

      val是固定的值;pattern是正则表达式。

    • while(condition) {...}

      统计/etc/fstab文件,U和/开头的行是处理对象。把每列的字符串的长度算出来,显示在列的后面,中间用冒号分隔。循环到最后一列时,打印换行。

      # awk '/^[U/]/{i=1;while(i<=NF) { printf "%s:%d ",$i,length($i); if(i==NF) {printf "
      "} i++} }' /etc/fstab
      /dev/mapper/centos-root:23 /:1 xfs:3 defaults:8 0:1 0:1
      UUID=3d3b316a-529e-484a-9895-e785fdde5365:41 /boot:5 xfs:3 defaults:8 0:1 0:1
      /dev/mapper/centos-home:23 /home:5 xfs:3 defaults:8 0:1 0:1
      /dev/mapper/centos-swap:23 swap:4 swap:4 defaults:8 0:1 0:1
      
    • do{...} while(condition)

    • for(expr1;expr2;expr3){...}

      统计/etc/fstab文件,U和/开头的行是处理对象。把每列的字符串的长度算出来,显示在列的后面,中间用冒号分隔。循环到最后一列时,打印换行。

      # awk '/^[U/]/{for(i=1;i<=NF;i++) { printf "%s:%d ",$i,length($i); if(i==NF) {printf "
      "} } }' /etc/fstab
      /dev/mapper/centos-root:23 /:1 xfs:3 defaults:8 0:1 0:1
      UUID=3d3b316a-529e-484a-9895-e785fdde5365:41 /boot:5 xfs:3 defaults:8 0:1 0:1
      /dev/mapper/centos-home:23 /home:5 xfs:3 defaults:8 0:1 0:1
      /dev/mapper/centos-swap:23 swap:4 swap:4 defaults:8 0:1 0:1
      

      遍历数组的特殊用法:for(var in array)

    • continue,bread[n](退出哪层循环)

    • next:提前退出当前行的处理,直接进入下一行。类似continue。

      显示uid是偶数的行。

      # awk -F: '{ if($3%2)next;print $1,$3}' /etc/passwd
      root 0
      daemon 2
      lp 4
      shutdown 6
      
    • delete arrary[index]:删除数组的某个元素

    • delete array:删除数组

    • exit:退出

    2,input statements

    3,output statements

    数组

    • 索引数组:索引是数字
    • 关联数组:索引是任意的字符串,字符串要用双引号括起来。

    当引用一个不存在的数组元素时,会自动创建之。数组索引是从1开始。

    判断某个索引是否存在,要使用特殊的语法:index in array

    第一个wk["tur"]=12222a的12222a没有用双引号括起来,打印wk["tur"]的值变成了12222,自动把a去掉了。

    # awk 'BEGIN{wk["mon"]="aaa";wk["tur"]=12222a; print wk["tur"]; print wk["mon"]}'
    12222
    aaa
    [root@localhost ~]# awk 'BEGIN{wk["mon"]="aaa";wk["tur"]="1222a"; print wk["tur"]; print wk["mon"]}'
    12222a
    aaa
    

    用for遍历数组,i是数组的索引,而不是数组元素的值。

    # awk 'BEGIN{wk["mon"]="aaa";wk["tur"]="12222a"} {for(i in wk)print i}' /etc/issue
    tur
    mon
    tur
    mon
    tur
    mon
    [root@localhost ~]# awk 'BEGIN{wk["mon"]="aaa";wk["tur"]="12222a"} {for(i in wk)print wk[i]}' /etc/issue
    12222a
    aaa
    12222a
    aaa
    12222a
    aaa
    

    统计每个状态出现的次数之和。

    # netstat -tan
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State
    tcp        0      0 0.0.0.0:111             0.0.0.0:*               LISTEN
    tcp        0      0 192.168.122.1:53        0.0.0.0:*               LISTEN
    tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
    tcp        0      0 127.0.0.1:631           0.0.0.0:*               LISTEN
    tcp        0      0 127.0.0.1:6011          0.0.0.0:*               LISTEN
    tcp        0     64 192.168.56.107:22       192.168.56.1:60328      ESTABLISHED
    tcp6       0      0 :::111                  :::*                    LISTEN
    tcp6       0      0 :::80                   :::*                    LISTEN
    tcp6       0      0 :::22                   :::*                    LISTEN
    tcp6       0      0 ::1:631                 :::*                    LISTEN
    tcp6       0      0 ::1:6011                :::*                    LISTEN
    # netstat -tan | awk '{if(NR==1 || NR==2)next; wk[$6]++} END{for(i in wk) printf "%s:%d times
    ", i,wk[i]}'
    LISTEN:10 times
    ESTABLISHED:1 times
    

    函数

    1,内置函数

    • rand():随机返回小于1的小数

    • split(要被分隔的串,存放分隔后的结果,分隔符):分隔字符串。

      # netstat -tnl | awk '/^tcp>/{split($4,ip,":"); print ip[1]}'
      0.0.0.0
      192.168.122.1
      0.0.0.0
      127.0.0.1
      127.0.0.1
      

    2,也支持自定义函数

    # c/c++ 学习互助QQ群:877684253 ![](https://img2018.cnblogs.com/blog/1414315/201811/1414315-20181106214320230-961379709.jpg) # 本人微信:xiaoshitou5854
  • 相关阅读:
    四十五、android camera
    MyEclipse优化技巧
    设置MyEclipse编码、补全快捷键、字体大小
    妈妈走开一会儿
    四十一、Android Notification通知详解
    四十三、设置Activity永不过期,即不执行onDestroy()
    七、oracle 表查询二
    四十七、实现调用Android手机的拍照功能
    四十四、Android之android:layout_weight详解
    一、oracle 高水位线详解
  • 原文地址:https://www.cnblogs.com/xiaoshiwang/p/12420899.html
Copyright © 2011-2022 走看看