zoukankan      html  css  js  c++  java
  • 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 命令也是比较有意思的,把输入传给另外一个命令作为参数。
  • 相关阅读:
    HDU 3081 Marriage Match II
    HDU 4292 Food
    HDU 4322 Candy
    HDU 4183 Pahom on Water
    POJ 1966 Cable TV Network
    HDU 3605 Escape
    HDU 3338 Kakuro Extension
    HDU 3572 Task Schedule
    HDU 3998 Sequence
    Burning Midnight Oil
  • 原文地址:https://www.cnblogs.com/xiaotlili/p/3210586.html
Copyright © 2011-2022 走看看