zoukankan      html  css  js  c++  java
  • Awk

    AWK:
    awk介绍:
      Linux 文本处理工具三剑客:grep、sed、awk
      其中grep是一种文本过滤工具,sed是文本行编辑器,而awk是一种报表生成器,就是对文件进行格式化处理的,但这里的格式化不是文件系统的格式化,而是对文件内容进行各种"排版",进而格式化显示

      在Linux之上我们使用的是GNU awk简称gawk,并且gawk就是awk的链接文件,因此系统上使用的awk和gawk是一样的。我们通过man gawk可以获得gawk的相关功能说明gawk-pattern scanning and processing language(模式扫描及处理语言),gawk是一种过程式编程语言。gawk还支持条件判断、数组、循环等编程语言中所有可以使用的功能,因此还可以把gawk称为一种脚本语言解释器。

      grep、egrep、fgrep:文本过滤工具:partten
      sed:行编辑器;模式空间、保持空间
      awk:报告生成器,格式化文本输出

      AWK:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出
      有多种版本:New awk(nawk)、GNU awk(gawk)
      [root@centos7 ~]# which awk
      /usr/bin/awk
      [root@centos7 ~]# ll /usr/bin/awk
      lrwxrwxrwx. 1 root root 4 Jul 25 23:58 /usr/bin/awk -> gawk

    基本用法:
      awk [options] 'program' var=value file…
      awk [options] -f programfile var=value file…
      awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file ...
     程序组成:awk程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成

      用法格式及选项:
      基本格式:awk [options] 'program' file…
      options(选项):
        -F 指明输入时用到的字段分隔符
       -v var=value 自定义变量

      program(编程语言):PATTERN{ACTION STATEMENT;...},通常是在单引号和双引号中
        PARTTERN 模式,部分决定动作语句何时触发及触发事件(BEGIN、END)
        ACTION STATEMENT 动作语句,可以由多个语句组成,各语句之间使用分号分隔:如print;printf

      分割符、域和记录:
      awk执行时,由分隔符分隔的字段(域);标记$1,$2..$n称为域标识。$0为所有域;注意:和shell中变量$符含义不同;文件的每一行称为记录;省略action,则默认执行print $0 的操作。

     awk工作原理:
      awk在处理文本时也是一次读取一行文本,然后根据输入分隔符(默认为空格字符)进行切片,切成n个片段,然后将每一片都赋予awk内部的一个变量当中进行保存,这些变量名为$1,$2,$3...一直到最后一个,awk就可以对这些片段进行单独处理,比如显示某一段或特定段,甚至可以对某些片段进行额外的的加工处理,比如计数、运算等。

      具体工作原理如下:
      第一步:执行BEGIN{action;… }语句块
      第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕
      第三步:当读至输入流末尾时,执行END{action;…}语句块

      BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
      END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
      Pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

    演示:
    [root@centos7 ~]# tail -5 /etc/fstab # 取/etc/fstab 的后五行
    UUID=5de91e7f-4334-4646-8bcf-7e8df5969f74 / xfs defaults 0 0
    UUID=abad3f46-4294-40b0-9d48-78c7e87cbfbf /boot xfs defaults 0 0
    UUID=01aef744-48b5-4346-ab7d-33150e05f3c7 /usr xfs defaults 0 0
    UUID=9765d553-e77b-48db-a4ff-502e43833384 swap swap defaults 0 0
    UUID=a42aca7a-085a-43c2-a22c-4f4aa6a22574 /testdir ext4 acl 0 0
    [root@centos7 ~]# tail -5 /etc/fstab |awk '{print $2,$3}' # 对读进来的每一行都执行打印第2和第3片段
    / xfs
    /boot xfs
    /usr xfs
    swap swap
    /testdir ext4
    [root@centos7 ~]# tail -5 /etc/fstab |awk '{print "hello",$2,$3}' # 自己加一个字段,注意要用逗号分隔
    hello / xfs
    hello /boot xfs
    hello /usr xfs
    hello swap swap
    hello /testdir ext4

    输出命令:print
      print格式:print item1, item2, ...
      要点:
      1、逗号分隔符;
      2、输出的各item可以是字符串,也可以是数值、当前记录的字段、变量或awk的表达式;
      3、如省略item,相当于print $0

    演示:
    [root@centos7 ~]# awk '{print "hello,awk"}' # 不管输入什么都只打印定义好的
    asdas
    hello,awk
    asfas
    hello,awk
    dddd
    hello,awk

    [root@centos7 ~]# awk -F: '{print}' /etc/passwd # 把/etc/passwd的每一行都打印一遍
    root:x:0:0:tcpdump,,62985600:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

    [root@centos7 ~]# awk -F: '{print "tao"}' /etc/passwd # /etc/passwd 的每一行输入进去之后都打印成 tao
    tao
    tao
    tao
    tao
    [root@centos7 ~]# awk -F: '{print $1}' /etc/passwd # 以:为分隔符,打印每一行的第一个片段
    root
    bin
    daemon
    adm
    lp

    [root@centos7 ~]# tail -5 /etc/fstab |awk '{print "hello",$2,$3}' # 自己加一个字段,注意要用逗号分隔
    hello / xfs
    hello /boot xfs
    hello /usr xfs
    hello swap swap
    hello /testdir ext4

    [root@centos7 ~]# awk -F: '{print $1" "$3}' /etc/passwd # 也可以用其他分隔符,但一定要加双引号。
    root 0
    bin 1
    daemon 2
    adm 3
    lp 4
    sync 5

    awk变量:内置和自定义变量
      内置变量
      FS 输入字段分隔符,默认为空白字符
        awk -v FS=':' '{print $1,$3,$7}' /etc/passwd
        awk –F: '{print $1,$3,$7}' /etc/passwd
      OFS 输出字段分隔符,默认为空白字符
        awk -v FS=':' -v OFS=':' '{print $1,$2,$3}' /etc/passwd
      RS 输入记录分隔符,指定输入时的换行符,原换行符仍有效
        awk -v RS=' ' '{print }' /etc/passwd
      ORS 输出记录分隔符,输出时用指定符号代替换行符
        awk-v RS=' ' -v ORS='###''{print }' /etc/passwd
      NF 字段数量
        awk -F:'{print NF}' /etc/fstab, 引用内置变量不用$
        awk -F: '{print $(NF-1)}' /etc/passwd
      NR 行号
        awk '{print NR}' /etc/fstab; awk END'{print NR}' /etc/fstab
      FNR 各文件分别计数,行号(多个文件时)
        awk '{print FNR}' /etc/fstab /etc/inittab
      FILENAME 当前文件名
        awk '{print FILENAME}' /etc/fstab
      ARGC 命令行参数的个数
        awk '{print ARGC}' /etc/fstab /etc/inittab
        awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
      ARGV 数组,保存的是命令行所给定的各参数
        awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab
        awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab

      自定义变量:变量名区分字符大小写
      通过-v选项定义变量
      -v var=value
      awk -v test='hello gawk' '{print test}' /etc/fstab
      awk -v test='hello gawk' 'BEGIN{print test}'
      在program直接定义变量
      awk'BEGIN{test="hello,gawk";print test}'

    内置变量演示:
    [root@centos7 ~]# awk -F: '{print $1,$3,$7}' /etc/passwd # 指明以":"作为输入字段分隔符,如果不指明的话以空白当做分隔符
    root 0 /bin/bash
    bin 1 /sbin/nologin
    daemon 2 /sbin/nologin
    adm 3 /sbin/nologin
    lp 4 /sbin/nologin
    [root@centos7 ~]# awk -F: -v OFS='=>' '{print $1,$3,$7}' /etc/passwd # 指明输入,输出字段分隔符
    root=>0=>/bin/bash
    bin=>1=>/sbin/nologin
    daemon=>2=>/sbin/nologin
    adm=>3=>/sbin/nologin
    lp=>4=>/sbin/nologin
    sync=>5=>/bin/sync

    [root@centos7 ~]# awk -F: -v ORS='###' '{print }' /etc/passwd # 指明输出时的换行符
    root:x:0:0:root:/root:/bin/bash###bin:x:1:1:bin:/bin:/sbin/nologin###daemon:x:2:2:daemon:/sbin:/sbin/nologin###......

    [root@centos7 ~]# awk -F: '{print NF}' /etc/passwd # 以":"为分隔符,打印每一行的字段数量
    7
    7
    7
    7
    7
    7
    7
    7
    7
    [root@centos7 ~]# awk -F: '{print $NF}' /etc/passwd # 这时的$NF=$7,因为NF为内之变量替换为7,所以会打印第7个字段
    /bin/bash
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin
    /sbin/nologin

    [root@centos7 ~]# awk '{print NR }' /etc/passwd # 显示行号
    1
    2
    3
    4
    5
    6
    7
    [root@centos7 ~]# awk '{print FNR }' /etc/fstab /etc/issue
    # 如果后面跟多个文件的话,要想显示每个文件的行数,变量为FNR,如果不加F,则行号累加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    1
    2
    3
    4
    5
    6
    [root@centos7 ~]# awk END'{print NR }' /etc/fstab # 显示最后一行的行号
    13
    [root@centos7 ~]# awk END'{print FNR }' /etc/fstab /etc/issue
    6

    [root@centos7 ~]# awk '{print FILENAME}' /etc/fstab # 显示当前文件名
    /etc/fstab
    /etc/fstab
    /etc/fstab
    /etc/fstab
    /etc/fstab
    /etc/fstab
    /etc/fstab
    /etc/fstab

    [root@centos7 ~]# awk '{print ARGC}' /etc/fstab /etc/inittab # 命令行参数个数,但会输入的每行都会显示一遍
    3
    3
    3
    3
    3
    [root@centos7 ~]# awk 'BEGIN {print ARGC}' /etc/fstab /etc/inittab
    3 # 加上BEGIN 只显示一次命令行参数个数
    [root@centos7 ~]# awk 'BEGIN {print ARGV[0]}' /etc/fstab /etc/inittab
    awk # 数组,显示的是命令行的第几个参数
    [root@centos7 ~]# awk 'BEGIN {print ARGV[1]}' /etc/fstab /etc/inittab
    /etc/fstab
    [root@centos7 ~]# awk 'BEGIN {print ARGV[2]}' /etc/fstab /etc/inittab
    /etc/inittab

    自定义变量演示:
    #通过过-v选项定义变量
    [root@centos7 ~]# awk -v test='hello gawk' '{print test}' /etc/fstab
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    hello gawk
    [root@centos7 ~]# awk -v test='hello gawk' 'BEGIN{print test}' /etc/fstab
    hello gawk

    #直接在programe中定义变量也可以;
    [root@centos7 ~]# awk 'BEGIN{test="hello,gawk";print test}'
    hello,gawk

    输出命令:printf
      格式化输出:printf "FORMAT",item1,item2,...
      1、必须指定FORMAT
      2、不会自动换行,需要显式给出换行控制符 ;
      3、FORMAT中需要分别为后面每个item指定格式符;

      格式符:与item一一对应
      %c 显示字符的ASCII码
      %d,%i 显示十进制整数
      %e,%E 科学计数法数值显示
      %f 显示为浮点数
      %g,%G 以科学计数法或浮点形式显示数值
      %s 显示字符串
      %u 无符号整数
      %% 显示%自身
      修饰符:
      #.# 第一个数字控制显示的宽度;第二个#表示小数点后精度;例如:%3.1f
      - 左对齐(默认右对齐);例如:%-15s
      + 显示数值的正负符号;例如:%+d

    演示:
    [root@centos7 ~]# awk -F: '{printf "%s",$1}' /etc/passwd # 表示把$1的内容显示在%s所在的位置,以字符串的形式显示;默认不自动换行;
    rootbindaemonadmlpsyncshutdownhalt...

    [root@centos7 ~]# awk -F: '{printf "%s ",$1}' /etc/passwd # 添加自动换行符
    root
    bin
    daemon
    adm
    lp
    sync
    shutdown
    halt

    [root@centos7 ~]# awk -F: '{printf "Username: %s ",$1}' /etc/passwd
    Username: root # 也可以添加字符串
    Username: bin
    Username: daemon
    Username: adm
    Username: lp
    Username: sync
    Username: shutdown

    [root@centos7 ~]# awk -F: '{printf "Username:%s UID:%d ",$1,$3}' /etc/passwd
    Username:root UID:0 # 格式和条目片段是对应的,每个片段会显示在对应格式符位置
    Username:bin UID:1
    Username:daemon UID:2
    Username:adm UID:3
    Username:lp UID:4
    Username:sync UID:5
    Username:shutdown UID:6

    [root@centos7 ~]# awk -F: '{printf "Username:%15s UID:%d ",$1,$3}' /etc/passwd
    Username: root UID:0 # 添加修饰符,显示宽度为15字符,默认为右对齐
    Username: bin UID:1
    Username: daemon UID:2
    Username: adm UID:3
    Username: lp UID:4
    Username: sync UID:5
    Username: shutdown UID:6
    Username: halt UID:7
    [root@centos7 ~]# awk -F: '{printf "Username:%-15s UID:%d ",$1,$3}' /etc/passwd
    Username:root UID:0 # 左对齐显示
    Username:bin UID:1
    Username:daemon UID:2
    Username:adm UID:3
    Username:lp UID:4
    Username:sync UID:5
    Username:shutdown UID:6

    操作符:
      1、算数操作符:
      x+y, x-y, x*y, x/y, x^y(x的y次方), x%y
      -x 转换为负数;
      +x 转换为数值;
      2、赋值操作符:
      =, +=, -=, *=, /=, %=, ^=, ++, --
      3、比较操作符:
      >, >=, <, <=, !=, ==
      4、模式匹配符:
      ~ 左边是否和右边匹配包含
      !~ 是否不匹配
      示例:
      cat /etc/passwd |awk '$0 ~ /root/' |wc -l
      cat /etc/passwd |awk '$0 !~ /root/' |wc -l
      5、逻辑操作符:
      &&,||,!
      示例:
      awk –F: '$3>=0 && $3<=1000 {print $1}' /etc/passwd
      awk -F: '$3 ==0 || $3>=1000 {print $1}' /etc/passwd
      awk -F: ‘!($3==0){print $1}' /etc/passwd
      awk -F: '!($3>=500) {print $3}}' /etc/passwd
      6、函数调用:
      function_name(argu1, argu2, ...)
     7、条件表达式:
      selector?if-true-expression:if-false-expression
    演示:
    # 显示用户的UID如果大等于1000则为普通用户,否则为管理员或系统用户,并定义格式输出
    [root@centos7 ~]# awk -F: '{$3>=1000?usertype="Common User":usertype="Sysadmin or SysUser";printf"%15s:%-s ",$1,usertype}' /etc/passwd
    root:Sysadmin or SysUser
    bin:Sysadmin or SysUser
    daemon:Sysadmin or SysUser
    adm:Sysadmin or SysUser
    lp:Sysadmin or SysUser
    sync:Sysadmin or SysUser
    shutdown:Sysadmin or SysUser
    halt:Sysadmin or SysUser
    mail:Sysadmin or SysUser
    operator:Sysadmin or SysUser
    games:Sysadmin or SysUser
    ftp:Sysadmin or SysUser
    nobody:Sysadmin or SysUser
    avahi-autoipd:Sysadmin or SysUser
    systemd-bus-proxy:Sysadmin or SysUser
    systemd-network:Sysadmin or SysUser
    dbus:Sysadmin or SysUser
    polkitd:Sysadmin or SysUser
    abrt:Sysadmin or SysUser
    colord:Sysadmin or SysUser
    libstoragemgmt:Sysadmin or SysUser
    setroubleshoot:Sysadmin or SysUser
    rpc:Sysadmin or SysUser
    rtkit:Sysadmin or SysUser
    chrony:Sysadmin or SysUser
    tss:Sysadmin or SysUser
    geoclue:Sysadmin or SysUser
    usbmuxd:Sysadmin or SysUser
    mysql:Sysadmin or SysUser
    pulse:Sysadmin or SysUser
    gdm:Sysadmin or SysUser
    rpcuser:Sysadmin or SysUser
    postfix:Sysadmin or SysUser
    sshd:Sysadmin or SysUser
    ntp:Sysadmin or SysUser
    apache:Sysadmin or SysUser
    tao:Common User

    PATTERN:
      PATTERN:根据pattern条件,过滤出匹配的行,再对这些行做处理

      1、如果未指定PATTERN:空模式则逐行匹配每一行
      2、/regular expression/:仅处理能够被模式匹配到的行,需要用/ /括起来(正则表达式过滤);
      示例:
      awk '/^UUID/{print $1}' /etc/fstab
      awk '!/^UUID/{print $1}' /etc/fstab
      3、relational expression: 关系表达式过滤;条件为"真"会被过滤出来
      真:结果为非0值、非空字符串、条件成立
      假:结果为0、空字符串、条件不成立
     示例:
      awk -F: '$3>=1000{print $1,$3}' /etc/passwd
      4、line ranges:行范围定界(通过两个模式匹配定界)
      start_pat,end_pat:/pat1/,/pat2/不支持直接给出数字格式
      示例:
      awk -F: '/^root/,/^nobody/{print $1}' /etc/passwd
      awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
      5、BEGIN/END模式:
      BEGIN{}: 仅在开始处理文本之前执行一次
      END{}:仅在文本处理完成之后执行一次
    演示:
    # 处理匹配到的模式
    [root@centos7 ~]# awk '/^UUID/{print $1}' /etc/fstab
    UUID=90880561-dca2-447b-a935-4c47e1bd03d8
    UUID=219cc6c3-bd54-4bac-a47f-b498c491107f
    UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d
    UUID=af279379-acbd-47f5-a814-870666bdd6d1
            # 对匹配到的模式取反
    [root@centos7 ~]# awk '!/^UUID/{print $1}' /etc/fstab
    #
    #
    #
    #
    #
    #
    #
    # 关系表达式,也可以称为比较表达式,条件为真,才会被处理。如果UID大于等于1000,则打印用户名和UID
    [root@centos7 ~]# awk -F: '$3>=1000{print $1,$3}' /etc/passwd
    nfsnobody 65534
    tao 1000

    # 表示最后一个字段等于/bin/bash,则打印用户名和UID
    [root@centos7 ~]# awk -F: '$NF=="/bin/bash"{print $1,$3}' /etc/passwd
    root 0
    tao 1000
    # 表示左边的字段信息能够被右边的模式所匹配,则打印第一个字段和最后一个字段
    [root@centos7 ~]# awk -F: '$NF~/bash/ {print $1,$NF}' /etc/passwd
    root /bin/bash
    tao /bin/bash

    [root@centos7 ~]# seq 10 |awk 'i=!i'
    1
    3
    5
    7
    9
    # 表示第一次被/^root/模式匹配到的行开始,到第一次被/^nobody/模式匹配到的行结束
    [root@centos7 ~]# awk -F: '/^root/,/^nobody/{print $1}' /etc/passwd
    root
    bin
    daemon
    adm
    lp
    sync
    shutdown
    halt
    mail
    operator
    games
    ftp
    nobody
    # 表示第二行到第十行,打印用户名
    [root@centos7 ~]# awk -F: '(NR>=2&&NR<=10){print $1}' /etc/passwd
    bin
    daemon
    adm
    lp
    sync
    shutdown
    halt
    mail
    operator

    [root@centos7 ~]# awk -F: 'BEGIN{print " username uid ----------------------"}'
    username uid
    ---------------------- # 打印表头

    [root@centos7 ~]# awk -F: 'BEGIN{print " username uid --------------------------"}{printf "%18s %3d ",$1,$3}' /etc/passwd
    username uid
    --------------------------
    root 0
    bin 1
    daemon 2
    adm 3
    lp 4
    sync 5
    shutdown 6

    [root@centos7 ~]# awk -F: 'BEGIN{print " username uid --------------------------"}{print $1,$3}END{print "======================= END"}' /etc/passwd
    username uid
    --------------------------
    root 0
    bin 1
    daemon 2
    adm 3
    lp 4
    sync 5
    dbus 81
    polkitd 997
    abrt 173
    colord 996
    tcpdump 72
    tao 1000
    =======================
    END

    awk控制语句:if-else
      语法:
      if(condition) statement [else statement]
      使用场景:对awk取得的整行或某个字段做条件判断

    命令演示:
    # 单分支语句
    [root@centos7 ~]# awk -F: '{if($3>=1000) print $1,$3}' /etc/passwd
    nfsnobody 65534
    tao 1000

    # 双分支语句,一定注意语法书写格式
    [root@centos7 ~]# awk -F: '{if($3>=1000) {printf "Common user: %s ",$1} else {printf "root or Sysuser: %s ",$1}}' /etc/passwd
    root or Sysuser: root
    root or Sysuser: bin
    root or Sysuser: daemon
    root or Sysuser: adm
    root or Sysuser: lp
    root or Sysuser: sync
    root or Sysuser: shutdown
    root or Sysuser: halt
    root or Sysuser: mail
    root or Sysuser: operator
    root or Sysuser: games
    root or Sysuser: ftp
    root or Sysuser: nobody
    root or Sysuser: avahi-autoipd
    root or Sysuser: systemd-bus-proxy
    root or Sysuser: systemd-network
    root or Sysuser: dbus
    root or Sysuser: polkitd
    root or Sysuser: abrt
    root or Sysuser: colord
    root or Sysuser: libstoragemgmt
    root or Sysuser: setroubleshoot
    root or Sysuser: rpc
    root or Sysuser: rtkit
    root or Sysuser: chrony
    root or Sysuser: tss
    root or Sysuser: geoclue
    root or Sysuser: usbmuxd
    root or Sysuser: mysql
    root or Sysuser: pulse
    root or Sysuser: gdm
    root or Sysuser: rpcuser
    Common user: nfsnobody
    root or Sysuser: postfix
    root or Sysuser: sshd
    root or Sysuser: ntp
    root or Sysuser: tcpdump
    Common user: tao
    # 对某个字段做条件判断
    [root@centos7 ~]# awk -F: '{if($NF=="/bin/bash") print $1}' /etc/passwd
    root
    tao
    # 如果字段大于5,就打印
    [root@centos7 ~]# awk '{if(NF>5) print $0}' /etc/fstab
    # Created by anaconda on Tue Aug 30 09:45:37 2016
    # Accessible filesystems, by reference, are maintained under '/dev/disk'
    # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
    UUID=90880561-dca2-447b-a935-4c47e1bd03d8 / xfs defaults 0 0
    UUID=219cc6c3-bd54-4bac-a47f-b498c491107f /boot xfs defaults 0 0
    UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d /usr xfs defaults 0 0
    UUID=af279379-acbd-47f5-a814-870666bdd6d1 swap swap defaults 0 0

    取磁盘利用率:
    # 以%为分隔符,取第一字段
    [root@centos7 ~]# df -h |awk -F[%] '{print $1}'
    Filesystem Size Used Avail Use
    /dev/sda2 40G 915M 40G 3
    devtmpfs 475M 0 475M 0
    tmpfs 489M 0 489M 0
    tmpfs 489M 6.7M 483M 2
    tmpfs 489M 0 489M 0
    /dev/sda3 20G 2.8G 18G 14
    /dev/sda1 485M 138M 348M 29
    tmpfs 98M 0 98M 0
    # 再取最后一个字段
    [root@centos7 ~]# df -h |awk -F[%] '{print $1}' |awk '{print $NF}'
    Use
    3
    0
    0
    2
    0
    14
    29
    0
    # 模式匹配,匹配以/dev开头的行,注意这里要对/ 转义,模式匹配一定要写在 “/ /”中
    [root@centos7 ~]# df -h |awk -F[%] '/^/dev/{print $1}' |awk '{print $1,$NF}'
    /dev/sda2 3
    /dev/sda3 14
    /dev/sda1 29
    # 如果利用率大于等于20,就打印第一字段
    [root@centos7 ~]# df -h |awk -F[%] '/^/dev/{print $1}' |awk '{if($NF>=20) print $1}'
    /dev/sda1

    awk控制语句:while循环
      语法:条件“真”,进入循环;条件“假”,退出循环
        while(condition) statement
      使用场景:
      1、对一行内的多个字段逐一做相同处理时使用
      2、对数组中的各元素逐一做相同处理时使用

    演示:
    # 取文件模式所匹配的行
    [root@centos7 ~]# awk '/[[:space:]]*linux16/{print}' /etc/grub2.cfg
    linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 ro rhgb quiet LANG=en_US.UTF-8
    linux16 /vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 ro rhgb quiet
    # 所匹配行的字段数量
    [root@centos7 ~]# awk '/[[:space:]]*linux16/{print NF}' /etc/grub2.cfg
    7
    6

    # 对每一行中各字段个数做统计。
    这里用到了while循环,当i小于等于字段数量时就执行打印这一字段,及字段长短,并且执行i++,注意循环体用{}括起来
    [root@centos7 ~]# awk '/[[:space:]]*linux16/{i=1;while(i<=NF) {print $i,length($i);i++ }}' /etc/grub2.cfg
    linux16 7
    /vmlinuz-3.10.0-327.el7.x86_64 30
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
    ro 2
    rhgb 4
    quiet 5
    LANG=en_US.UTF-8 16
    linux16 7
    /vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
    ro 2
    rhgb 4
    quiet 5

    # 在上题的基础之上嵌套了一个if语句,表示如果字符长度大于7才打印,注意这里的{}表示的意义,最外面一层是整个的处理语句,倒数第二层表示循环体,最里面的表示if语句的执行动作,i++是while语句的,用分号分开
    [root@centos7 ~]# awk '/[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7) {print $i,length($i)};i++}}' /etc/grub2.cfg
    linux16 7
    /vmlinuz-3.10.0-327.el7.x86_64 30
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
    LANG=en_US.UTF-8 16
    linux16 7
    /vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46

    awk控制语句:do-while循环
      语法:
      do statement while(condition)
      意义:无论真假,至少执行一次循环体
      演示:
     [root@centos7 ~]# awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
     5050

    awk控制语句:for循环
      语法:for(expr1;expr2;expr3) statement
      for(variable assignment;condition;iterationprocess) {for-body}
      特殊用法:能够遍历数组中的元素;
     语法:for(varin array) {for-body}

    演示:
    [root@centos7 ~]# awk '/[[:space:]]*linux16/ {for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
    linux16 7
    /vmlinuz-3.10.0-327.el7.x86_64 30
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
    ro 2
    rhgb 4
    quiet 5
    LANG=en_US.UTF-8 16
    linux16 7
    /vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
    ro 2
    rhgb 4
    quiet 5

    [root@centos7 ~]# awk '/[[:space:]]*linux16/ {for(i=1;i<=NF;i++) {if(length($i)>=7) print $i,length($i)}}' /etc/grub2.cfg
    linux16 7
    /vmlinuz-3.10.0-327.el7.x86_64 30
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46
    LANG=en_US.UTF-8 16
    linux16 7
    /vmlinuz-0-rescue-a7ea085c1be64e7386b85deb2bfc1f18 50
    root=UUID=90880561-dca2-447b-a935-4c47e1bd03d8 46


    break和continue
      break [n] 终止本层循环
      continue [n] 提前结束本次循环进入下一轮循环

    next
     提前结束对本行处理而直接进入下一行处理(awk自身循环读取文件的每一行)
    命令演示:
    # 表示用户的ID号如果不为偶数,就提前终止这一行,直接进入下一行处理。
    [root@centos7 ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
    root 0
    daemon 2
    lp 4
    shutdown 6
    mail 8
    games 12
    ftp 14
    avahi-autoipd 170
    systemd-network 998
    colord 996
    setroubleshoot 994
    rpc 32
    rtkit 172
    geoclue 992
    gdm 42
    nfsnobody 65534
    sshd 74
    ntp 38
    tcpdump 72
    tao 1000

    # 和上面表示的结果是相同的,但方法和意义不同
    [root@centos7 ~]# awk -F: '{if($3%2==0) print $1,$3}' /etc/passwd
    root 0
    daemon 2
    lp 4
    shutdown 6
    mail 8
    games 12
    ftp 14
    avahi-autoipd 170
    systemd-network 998
    colord 996
    setroubleshoot 994
    rpc 32
    rtkit 172
    geoclue 992
    gdm 42
    nfsnobody 65534
    sshd 74
    ntp 38
    tcpdump 72
    tao 1000
    awk数组

    关联数组:
      array [index-expression]
      index-expression:
      1、索引可使用任意字符串;字符串要使用双引号括起来
      2、如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
      3、若要判断数组中是否存在某元素,要使用“index in array”格式进行遍历
      4、若要遍历数组中的每个元素,要使用for循环

      for(varin array) {for-body}
      注意:var会遍历array的每个索引

    演示:
    [root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekday["tue"]="Tuesday";print weekdays["mon"]}'
    Monday
    [root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["tue"]}'
    Tuesday

    遍历数组中的每个元素:for
    [root@centos7 ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) {print weekdays[i]}}'
    Tuesday
    Monday

    [root@centos7 ~]# netstat -tan |awk '/^tcp>/{print}'
    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:25 0.0.0.0:* LISTEN
    tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN
    tcp 0 52 10.1.249.203:22 10.1.250.25:51498 ESTABLISHED

    # 本题为第二种情况,数组元素事先不存在,在引用时awk会自动创建此元素,其初始值为“空串”也就是0。题目中,$NF变量作为数组的索引下标,其个数,出现一次就自加,自加的结果为数组元素的值;定义的for循环中的变量i为数组中的索引下标,state[i]才是数组中元素的值,最后打印数组中的索引下标和数组元素。
    [root@centos7 ~]# netstat -tan |awk '/^tcp>/{state[$NF]++}END{for(i in state) {print i,state[i]}}'
    LISTEN 4
    ESTABLISHED 1

    # 统计/etc/fstab文件中每个文件系统类型出现的次数
    [root@centos7 ~]# awk '/^UUID/{print}' /etc/fstab
    UUID=90880561-dca2-447b-a935-4c47e1bd03d8 / xfs defaults 0 0
    UUID=219cc6c3-bd54-4bac-a47f-b498c491107f /boot xfs defaults 0 0
    UUID=409f2fa0-f642-4cc2-9ed7-b20bda111d8d /usr xfs defaults 0 0
    UUID=af279379-acbd-47f5-a814-870666bdd6d1 swap swap defaults 0 0

    [root@centos7 ~]# awk '/^UUID/{fs[$3]++}END{for(i in fs) {print i,fs[i]}}' /etc/fstab
    swap 1
    xfs 3

    # 统计指定文件中每个单词出现的次数(行内字段遍历)
    # 因为是对整个文件做遍历,所以不用过滤行,然后遍历每一行中单词(默认空格分隔为一个单词)出现的个数,最后打印索引下标和元素个数
    [root@centos7 ~]# awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(i in count) {print i,count[i]}}' /etc/fstab
    Tue 1
    man 1
    and/or 1
    maintained 1
    xfs 3
    Accessible 1
    # 7
    30 1
    are 1
    defaults 4
    UUID=219cc6c3-bd54-4bac-a47f-b498c491107f 1
    blkid(8) 1
    / 1

    awk函数
      数值处理:
      rand() 返回0和1之间一个随机数
      字符串处理:
      length([s]) 返回指定字符串的长度
      sub(r,s,[t]) 在t字符串搜索能够被r表示的模式所匹配的内容,并将第一个匹配的内容替换为s
      gsub(r,s,[t]) 对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容
      split(s,array,[r]) 以r为分隔符切割字符s,并将切割后的结果保存至array所表示的数组中

    示例:
    # 数值处理,rand()示例(多次生成一个随机数是一样的)
    [root@centos7 ~]# awk 'BEGIN{print rand()}'
    0.237788
    [root@centos7 ~]# awk 'BEGIN{print rand()}'
    0.237788
    [root@centos7 ~]# awk 'BEGIN{print rand()}'
    0.237788
    [root@centos7 ~]# awk 'BEGIN{print rand()}'
    0.237788

    #生成10个1-100之间的随机数
    [root@centos7 ~]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100) }'
    51
    40
    86
    36
    75
    30
    14
    7
    58
    96

    # 把第一个字段(2008:08:08)中第一次查找到的 :替换为“”空
    [root@centos7 ~]# echo "2008:08:08 08:08:08" | awk 'sub(/:/,"",$1)'
    200808:08 08:08:08

    #把第一个字段中所有的 :替换为空
    [root@centos7 ~]# echo "2008:08:08 08:08:08" | awk 'gsub(/:/,"",$1)'
    20080808 08:08:08

    #取出tcp连接的所有远端地址
    [root@centos7 ~]# netstat -tan | awk '/^tcp>/{split($5,ip,":");print ip[1]}'
    0.0.0.0
    0.0.0.0
    0.0.0.0
    0.0.0.0
    10.1.250.25

    # 相当于嵌套了一个数组,对ip[1]数组中的元素做统计
    [root@centos7 ~]# netstat -tan | awk '/^tcp>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) print i,count[i]}'
    0.0.0.0 4
    10.1.250.25 1

  • 相关阅读:
    Setting up SharePoint Blogs, Wikis, and Announcements
    Reports 将透视表显示成没有级联关系的普通表
    TF80012: The document cannot be opened because there is a problem with the installation of the Microsoft Visual Studio v
    项目干系人分析的“四步法”
    Overload和Override的区别
    Add and Customize a Type of Work Item
    将所有的非DLL, PDB文件从一个位置Copy到另外一个位置,相同文件跳过
    如何删除工作项
    No Excel Calculation Services is available in the farm
    SPORTINGLIFE.COM
  • 原文地址:https://www.cnblogs.com/Link-Luck/p/9853421.html
Copyright © 2011-2022 走看看