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
  • 相关阅读:
    73. Set Matrix Zeroes
    289. Game of Live
    212. Word Search II
    79. Word Search
    142. Linked List Cycle II
    141. Linked List Cycle
    287. Find the Duplicate Number
    260. Single Number III
    137. Single Number II
    Oracle EBS中有关Form的触发器的执行顺序
  • 原文地址:https://www.cnblogs.com/xiaoshiwang/p/12420899.html
Copyright © 2011-2022 走看看