• linux awk命令


    awk

    语法
        awk [options] 'commands' files
     option
      -F 定义字段分隔符,默认的分隔符是连续的空格或制表符
         使用option中的-F参数定义间隔符号
         用$1,$2,$3等的顺序表示files中每行以间隔符号分隔的各列不同域
         NF变量表示当前记录的字段数
      -v 定义变量并赋值 也可以借用次方式从shell变量中引入

     command
      读前处理 行处理 读后处理
      1.读前处理 BEGIN{awk_cmd1;awk_cmd2}
      2.行处理:定址 命令
         定址方法: 正则,变量,比较和关系运算
       正则需要用//包围起来
         ^ 行首
         $ 行尾
         . 除了换行符以外的任意单个字符
         * 前导字符的零个或多个
         .* 所有字符
         [] 字符组内的任一字符
         [^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)
         ^[^] 非字符组内的字符开头的行
         [a-z] 小写字母
         [A-Z] 大写字母
         [a-Z] 小写和大写字母
         [0-9] 数字
         < 单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词
         > 单词尾

       扩展正则 加 -r 参数 或转义
        sed -n '/roo?/p' /etc/passwd 
         sed -rn '/roo?/p' /etc/passwd
         ? 前导字符零个或一个
         + 前导字符一个或多个
         abc|def abc或def
         a(bc|de)f abcf 或 adef
         x{m}   x出现m次
         x{m,}  x出现m次至多次(至少m次)
         x{m,n} x出现m次至n次

       NR变量定址
                  NR 表示AWK读入的行数
           FNR表示读入行所在文件中的行数
       # awk '{print NR,FNR,$1}' file1  file2
       1 1 aaaaa
       2 2 bbbbb
       3 3 ccccc
       4 1 dddddd
       5 2 eeeeee
       6 3 ffffff
       #
              逻辑运算 可直接引用域进行运算
        == >= <= != > < ~ !~
       # awk 'NR==1 {print}' /etc/passwd
       root:x:0:0:root:/root:/bin/bash
       #
      3.命令 {print $0}
      4.读后处理 END {awk_cmd1;awk_cmd2;}


    AWK变量
     NR    当前记录的个数(全部文件连接后的统计)
     FNR   当前记录的个数(仅为当前文件的统计,非全部)
     FS    字段分隔符 默认为连续空格或制表符,可以使用多个不同的符号做分隔符 -F[:/]
     OFS   输出字符的分隔符 默认是空格
      # awk -F: 'OFS="=====" {print $1,$2}' /etc/passwd
      root=====x
     NF    当前读入行的字段个数
     ORS   输出记录分隔符 默认是换行
      # awk -F: 'ORS="=====" {print $1,$2}' /etc/passwd
      root x=====bin x=====
     FILENAME 当前文件名

    引用shell变量的方法
     # a=root
     # awk -v var=$a -F: '$1 == var {print $0}' /etc/passwd
     或者 把整个命令拆开传递,让shell变量外露,
     # awk -F: '$1 == "'$a'" {print $0}' /etc/passwd
     # a=NF
     # awk -F: '{print $'$a'}' /etc/passwd

    操作符
     赋值
      = += -= /= *=
     逻辑与 逻辑或 逻辑非
      && || !
     匹配正则或不匹配,正则需要用 /正则/ 包围住
      ~  !~
     关系 比较字符串时要把字符串用双引号引起来
      < <= > >= != ==
     字段引用
      $ 字段引用需要加$,而变量引用直接用变量名取
     运算符
      + - * / % ++ --
     转义序列
      \ 自身
      $ 转义$
       制表符
       退格符
       回车符
       换行符
      c 取消换行


    试做
        打印uid在30~40范围内的用户名。
        打印第5-10行的行号和用户名
        打印奇数行
        打印偶数行
        打印字段数大于5的行
        打印UID不等于GID的用户名
        打印没有指定shell的用户
        打印1..1000以内的7的倍数和包含7的数
       
       

    流程控制
     分支结构

     if (条件) 动作
      若有多个动作,则要用大括号将动作体包含起来  if (条件) {动作1;动作2}
     # awk -F: '{if ($1 == "root") print $1}' /etc/passwd
     root
     #
     # awk -F: '{if ($1 == "root") {print $1;print $6}}' /etc/passwd
     root
     /root
     #
     
     if (条件1)
      动作1
     else
      动作2
     # awk -F: '{if ($1 == "root"){print $1}else print $6}' /etc/passwd
     # awk -F: '{if ($1 == "root") print $1;else print $6}' /etc/passwd
     上面两个命令是等价的,要么用分号隔开,表示第一个动作体的结束,要么将动作体用大括号定位范围
     
     if (条件 1)
      动作1
     else if(条件 2)
      动作2
     else if(条件 3)
      动作3
     else
      动作4
     # awk -F: '{if ($1 == "root") print $1;else if ($1 == "seker") print $6;else if ($1 == "zorro") print $7;else print NR}' /etc/passwd
     root
     2
     3
     ...
     33
     /home/seker
     /bin/bash
     36

     条件 ? 动作1 : 动作2
     expr?action1:action2
     # awk -F: 'var=($3 >= 500)?$1:"system_user" {print $1" "$3" "var}' /etc/passwd
     # awk -F: '{print ($3>500?$1:$2)}' /etc/passwd

    试做
       将系统用户按UID分组标记 0 admin; 1-499 sysuser; 500+ users

    输出样式
     %s是字符类型,%d数值类型
     printf默认是不输出换行的所以要加
     10和7是偏移量
     默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充
     注意:格式与输出列之间要有逗号
     # awk -F: '{printf "%-10s %-10d %s ",$1,$3,$7}' /etc/passwd


    读前处理和读后处理
     # awk -F: 'BEGIN{i=1} {i++} END {print i}' /etc/passwd
     47
     #
     # awk -F: 'BEGIN {print NR,NF}' /etc/passwd
     0 0
     #
     # awk -F: 'END {print NR,NF}' /etc/passwd
     46 7
     #
    试做
        找出普通用户的用户名并统计数量
     # awk -F: 'BEGIN{i=0} $3 >= 500 {print $1;i++} END {print i}' /etc/passwd
        计算UID相加的总和;计算GID相加的总和
        计算VSZ和RSS各自的和 并以M单位显示


     循环语句
       while(条件) {
      动作
      条件运算
       }
     # awk -F: '{while($3<3) {print $3,$1;$3++}}' /etc/passwd
     0 root
     1 root
     2 root
     1 bin
     2 bin
     2 daemon
     #
     BEGIN块可以独立使用,不需要引入文件
     # awk 'BEGIN{i=1;while(i<100) {print i;i++}}'
    试做
        打印100以内的偶数
        # awk 'BEGIN{i=1;while(i<100) {if (i%2==0) print i;i++}}'
     
     x=1
     do {
      动作1
      x++
       } while (x<5)
     # awk 'BEGIN{i=5;do{print i;i++}while(i<10)}'
     # awk 'BEGIN{i=5;do{print i;i++}while(i<1)}'
     

     for(预置;条件;递增) {
      动作
       }
     # awk 'BEGIN {for (x=1;x<=4;x++) print x }'
     1
     2
     3
     4
     #
        # awk 'BEGIN{for (i=1;i<=4;i++) {for (j=1;j<=4;j++) print i,j}}'

     
    试做
        使用嵌套的for循环,打印100-999之间的数,个十百位分别用一个for来打印
     # awk 'BEGIN{OFS="";for (i=1;i<=9;i++) {for (j=0;j<=9;j++) {for (n=0;n<=9;n++) print i,j,n}}}'
        打印乘法口诀表
     # cat 99.sh
     #!/bin/bash
     awk 'BEGIN{
      for(i=1;i<10;i++)
      {
       for(j=1;j<=i;j++)
        printf "%d*%d=%d ",j,i,j*i
       print
      } 

     }'
     #

        打印金字塔
     # cat jin.sh
     #!/bin/bash
     awk 'BEGIN{
      num=5
      for(i=1;i<=num;i++)
      { 
       for (n=1;n<=num-i;n++)
        printf "%s"," "
       for (j=1;j<=2*i-1;j++)
           printf "%s","*"
       print
      }
     }'
     #

        逆序输出每个字段
     达到这样既可
     /bin/bash
     /root
     root
     0
     0
     x
     root


     # awk -F: '{for (x=NF;x>0;x--) print $x}' /etc/passwd

    继续解决上一个试做题的格式问题
     # awk -F: '/bash$/{for (x=NF;x>0;x--) printf "%-13s",$x;printf " "}' /etc/passwd

     跳转语句
     break 跳出循环
     # awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) break;print x }}'
     1
     2
     
     continue 在达到循环底部之前终止当前循环 从新开始下一次循环
     # awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) continue;print x }}'
     1
     2
     4

     next 读入下一行 同时返回脚本顶部 这样可以避免对当前行执行其他操作
     # awk -F: 'NR > 5 {next} {print $1} END {print NR}' /etc/passwd
     root
     bin
     daemon
     adm
     lp
     46
     #
     exit 使读取动作终止 并将控制移动到END,如果没有END则终止脚本
     # awk -F: 'NR > 5 {exit} {print $1} END {print NR}' /etc/passwd
     root
     bin
     daemon
     adm
     lp
     6
     #

    数组
     自定义数组
     # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";print ary[1],ary[2]}'
     seker zorro
     #
     # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";for(i in ary) print ary[i]}'
     seker
     zorro
     #
     删除一个元素 对元素给空值并不能清除这个元素 要想清除一个元素需要使用delete ary[idx]
     # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";ary[3]="blues";ary[2]="";for(i in ary) print ary[i]}'
     seker

     blues
     # awk 'BEGIN {ary[1]="seker";ary[2]="zorro";ary[3]="blues";delete ary[2];for(i in ary) print ary[i]}'
     seker
     blues
     #

     循环产生数组和取出数组
     # awk 'BEGIN{n=5;for (i=1;i<=n;i++) ary[i]=i+100;for(m in ary) print m,ary[m]}'
     4 104
     5 105
     1 101
     2 102
     3 103
     #
     
     # awk -F: '{ary[NR]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd
     1 root
     2 bin
     3 daemon
     4 adm
     5 lp
     6 sync
     7 shutdown
     8 halt
     9 mail
     # awk -F: '{ary[$3]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd
     10 uucp
     11 operator
     12 games
     13 gopher
     14 ftp
     32 rpc
     37 rpm

     ARGV  命令行中参数数组
      # awk '{for (i in ARGV) {print i,ARGV[i]}}'  /etc/passwd /etc/fstab
      0 awk
      1 /etc/passwd
      2 /etc/fstab
      #### i 为下标; ARGV[i] 下标为i的值
    试做
        统计每种shell被使用的次数


    函数

    算术函数 int
    [root@stu254 ~]# awk 'BEGIN {print int(3.9415)}'
    3
    [root@stu254 ~]#


    随机数函数 rand()  srand()
    rand() 取值 0 > r < 1 之间 默认的种子是系统时间 精确到秒
    srand()取值 0 > r < 1 之间 可以指定种子来影响rand()取值数 默认是系统时间 精确到秒

    [root@stu254 ~]# awk 'BEGIN {srand(222);print int(rand()*100000000)}'
    90204196
    [root@stu254 ~]#

    字符串函数
    substr(s,x[,y])
     返回字符串s中从位置x起至y的子串,如果没有给出y,则从x开始到结束.
    [root@stu254 ~]# awk 'BEGIN {x="abcdefxyz";print substr(x,4,3)}'
    def
    [root@stu254 ~]#

    大写小写
    sprintf() 本身并不能打印,做格式转换,将数字转换成ASCII字符
    # awk 'BEGIN {for(i=97;i<=122;++i) print tolower(toupper(sprintf("%c",i)))}'

    字符串长度
    length()  如果没有给定字符串则使用$0
    [root@stu254 ~]# awk 'BEGIN {print length("abcdefxyz")}'
    9

    gsub(/abc/,"ABC",x) 全局字符串替换
     从x中用匹配的abc正则替换成ABC
    [root@stu254 ~]# awk 'BEGIN {x="xyzabcxyzabcxyz";gsub(/abc/,"ABC",x);print x}'
    xyzABCxyzABCxyz
    [root@stu254 ~]#  sub 第一次的替换
    [root@stu254 ~]# awk 'BEGIN {x="xyzabcxyzabcxyz";sub(/abc/,"ABC",x);print x}'
    xyzABCxyzabcxyz
    [root@stu254 ~]#

           gensub(r, s, h [, t])   Search the target string t for matches of the reg-
                                   ular  expression  r.   If  h is a string beginning
                                   with g or G, then replace all matches of r with s.
                                   Otherwise, h is a number indicating which match of
                                   r to replace.  If t is not supplied,  $0  is  used
                                   instead.
    gensub(正则,替换,范围,目标串)
    [root@tch254 ~]# awk 'BEGIN{print gensub("zorro","AAAA","2","seker zorro zorro seker")}'
    seker zorro AAAA seker
    [root@tch254 ~]# echo seker zorro zorro seker | sed 's/zorro/AAAA/2'
    seker zorro AAAA seker
    [root@tch254 ~]#
    [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","g");print}'
    seker AAAA AAAA seker
    [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","2");print}'
    seker zorro AAAA seker
    [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","h");print}'
    seker AAAA zorro seker
    [root@tch254 ~]# echo seker zorro zorro seker | awk '{$0=gensub("zorro","AAAA","1");print}'
    seker AAAA zorro seker
    [root@tch254 ~]#


    系统函数
    getline 

    交互输入
    [root@stu254 ~]# awk -F: 'BEGIN {printf "Enter Number: ";getline ;for(i=1;i<=$0;i++) print i}'
    Enter Number: 3
    1
    2
    3
    [root@stu254 ~]#

    将输入赋值给变量
    [root@stu254 ~]# awk -F: 'BEGIN {printf "Enter Number: ";getline NUM;for(i=1;i<=NUM;i++) print i}'
    Enter Number: 3
    1
    2
    3
    [root@stu254 ~]#

    从文件中读入
    [root@tch254 ~]# awk -F: 'BEGIN {getline < "/etc/passwd" ; print $3" "$1}'
    0 root
    [root@tch254 ~]#

    #awk -F: 'BEGIN {while (getline < "/etc/passwd" > 0) print $3" "$1}'

       getline < "/etc/passwd" 从文件中读入,每次读取一行,默认情况下读取的次数等于awk自身引入文件的行数
          也可以放到for中来控制读取的次数
         > 0    测试读取的返回值,成功返回1,失败返回-1,0文件末尾

    从命令输出中输入
    [root@stu254 ~]# awk 'BEGIN {"uname -a"|getline ;print $3}'
    2.6.18-53.el5
    [root@stu254 ~]#

     


    system(command)
     系统命令要用""引起来
    [root@stu254 ~]# rm -rf abc/
    [root@stu254 ~]# awk 'BEGIN {if(system("mkdir abc") != 0 ) print "ERR"}'
    [root@stu254 ~]# awk 'BEGIN {if(system("mkdir abc") != 0 ) print "ERR"}'
    mkdir: 无法创建目录 “abc”: 文件已存在
    ERR
    [root@stu254 ~]#
    [root@tch254 ~]# awk 'BEGIN {if(system("mkdir abc 2>/dev/null") != 0 ) print "ERR"}'
    ERR
    [root@tch254 ~]# 

    awk脚本的介绍 -f 与 #!/bin/awk -f

    使用awk添加系统用户
    [root@mail ~]# cat useradd.awk
    #!/bin/awk -f

    {
     system("useradd "$1";echo "$2"|passwd --stdin "$1)
    }
    [root@mail ~]# cat username
    myname 1234
    [root@mail ~]#
    [root@mail ~]# ./useradd.awk ./username
    Changing password for user myname.
    passwd: all authentication tokens updated successfully.
    [root@mail ~]#

    ls -l -t |grep txt | head -n 3 | tail -n 1| awk -F' ' '{print $NF}' | xargs rm -f

    删除文件夹里面倒数第二新的log文件

    ls命令的-t ,让文件按照时间排序,

     
    head -n 2 | tail -n 1| 取文本的第二行
     
    awk -F' ' '{print $NF}' 打印一行中最后的一列
     
    xargs 命令也是比较有意思的,把输入传给另外一个命令作为参数。
  • 相关阅读:
    JVM如何执行方法调用
    JVM如何实现反射
    JVM是如何处理异常的
    Java类加载
    windows-Kafka安装
    Google Eventbus简单使用
    队列c#版
    python 元类

    Spring Mvc 笔记二之异常和文件上传
  • 原文地址:https://www.cnblogs.com/xiaotlili/p/3210586.html
Copyright © 2020-2023  润新知