zoukankan      html  css  js  c++  java
  • linux之awk基础

    第一章

    1.awk 简介

    awk不仅仅时linux系统中的一个命令,而且是一种编程语言,可以用来处理数据和生成报告(excel)。处理的数据可以是一个或多个文件,可以是来自标准输入,也可以通过管道获取标准输入,awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更为复杂的运用。本章主要讲解awk命令的运用。

    2.awk 的格式

    • awk指令是由模式,动作,或者模式和动作的组合组成。
    • 模式既pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把他理解为一个条件。
    • 动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。比如awk使用格式
    • pattern既模式,也可以理解为条件。
    • action既动作,可以理解为干啥,找到人之后你要做什么

    3.awk 内置变量

    ARGC               命令行参数个数
    ARGV               命令行参数排列
    ENVIRON            支持队列中系统环境变量的使用
    FILENAME           awk浏览的文件名
    FNR                浏览文件的记录数
    FS                 设置输入域分隔符,等价于命令行 -F选项
    NF                 浏览记录的域的个数
    NR                 已读的记录数
    OFS                输出域分隔符
    ORS                输出记录分隔符
    RS                 控制记录分隔符

     此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。

    第二章 实战

    [root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10{print NR,$1}' /etc/passwd
    5 lp
    6 sync
    7 shutdown
    8 halt
    9 mail
    10 operator
    [root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10{print $1}' /etc/passwd
    lp
    sync
    shutdown
    halt
    mail
    operator
    [root@bogon ~]#

    命令解释

    -F 分隔符:  

    NR >=5 && NR<=10 这部分表示模式,是一个条件,表示取第5行到第10行。

    {print NR,¥1} :表示输出行号和$1第一列

    2. 只有模式

    [root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10' /etc/passwd
    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
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin

    命令解释:

    这里少了动作:{print NR,$1} 所以就输出了 NR>=5 &&NR<=10 第5 -10 行

    3. 只有动作

    [root@bogon ~]# awk -F':' '{print NR,$1}' /etc/passwd
    1 root
    2 bin
    3 daemon
    4 adm
    5 lp
    6 sync
    7 shutdown
    8 halt
    9 mail
    10 operator
    11 games
    12 ftp
    13 nobody
    14 systemd-network

    命令说明:
    -F指定分隔符为冒号
    这里没有条件,表示对每一行都处理
    {print NR,$1}表示动作,显示NR行号与$1第一列
    这里要理解没有条件的时候,awk会处理每一行。

    4.多个模式和动作

    [root@bogon ~]# awk -F":" 'NR==1{print NR,$1}' /etc/passwd
    1 root
    [root@bogon ~]# awk -F":" 'NR==1{print NR,$1}NR==2{print NR,$NF}' /etc/passwd
    1 root
    2 /sbin/nologin
    [root@bogon ~]#

    命令解释:

    -F 以冒号为分隔符

    这里有多个条件与动作的组合
    NR==1表示条件,行号(NR)等于1的条件满足的时候,执行{print NR,$1}动作,输出行号与第一列。
    NR==2表示条件,行号(NR)等于2的条件满足的时候,执行{print NR,$NF}动作,输出行号与最后一列($NF)

    5.文件处里过程

    [root@bogon ~]# awk 'NR>=2{print NR,$0}' /test/files/awkfile.txt
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    6 sync:x:5:0:sync:/sbin:/bin/sync
    7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    8 halt:x:7:0:halt:/sbin:/sbin/halt
    9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10 operator:x:11:0:operator:/root:/sbin/nologin
    [root@bogon ~]#

    命令说明:
    条件NR>=2,表示行号大于等于2时候,执行{print $0}显示整行。
    awk是通过一行一行的处理文件,这条命令中包含模式部分(条件)和动作部分(动作),awk将处理模式(条件)指定的行

    6.awk 小结

    1)awk读入第一行内容

    2)判断是否符合模式中的条件NR>=2

    a,如果匹配则执行对应的动作{print $0}
    b,如果不匹配条件,继续读取下一行

    3)继续读取下一行
    4)重复过程1-3,直到读取到最后一行(EOF:end of file)

    第三章

    1.记录和字段

    接下来我给大家带来两个新概念记录和字段,这里为了方便大家理解可以把记录就当作行即记录==行,字段相当于列,字段==列。

    名称含义
    record 记录,行
    field

    域,区域,字段,列

    2.

    [root@bogon ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /test/files/awkfile.txt
    1 root:x:0:0:root:
    2 root:
    3 bin
    4 bash
    bin:x:1:1:bin:
    5 bin:
    6 sbin
    7 nologin
    daemon:x:2:2:daemon:

    命令解释

    在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。
    我们设置RS(记录分隔符)的值为“/”,表示一行(记录)以“/”结束
    在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些 (回车换行符), 也是字符哦。

    [root@bogon ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /test/files/awkfile.txt
    1 root:x:0:0:root:
    2 root:
    3 bin
    4 bash
    bin:x:1:1:bin:
    5 bin:
    6 sbin
    7 nologin
    daemon:x:2:2:daemon:
    8 sbin:

    命令说明:
    在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。
    我们设置RS(记录分隔符)的值为“/”,表示一行(记录)以“/”结束
    在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些 (回车换行符), 也是字符哦。

    对$0的认识

    • 如1.7.2的例子,可以看出awk中$0表示整行,其实awk使用$0来表示整条记录。记录分隔符存在RS变量中,或者说每个记录以RS内置变量结束。
    • 另外,awk对每一行的记录号都有一个内置变量NR来保存,每处理完一条记录,NR的值就会自动+1
    • 行(记录):默认以 (回车换行)结束。而这个行的结束不就是记录分隔符嘛。
    • 所以在awk中,RS(记录分隔符)变量表示着行的结束符号(默认是回车换行).

    [root@chensiqi1 ~]# awk '{print NR,$0}' /server/files/awkfile.txt
    1 root:x:0:0:root:/root:/bin/bash
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    6 sync:x:5:0:sync:/sbin:/bin/sync
    7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    8 halt:x:7:0:halt:/sbin:/sbin/halt
    9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

    命令说明:
    NR既number of record,当前记录的记录号,刚开始学也可以理解为行号。
    $0表示整行或者说整个记录

     第4章

    实战1

    [root@bogon ~]# echo "I am test,my qq is 222222">>/test/files/test.txt
    [root@bogon ~]# cat /test/files/test.txt
    I am test,my qq is 222222
    [root@bogon ~]# awk -F "[ ,]" '{print $3,$NF}' /test/files/test.txt
    test 222222
    [root@bogon ~]# awk -F "[,]" '{print $3,$NF}' /test/files/test.txt
     my qq is 222222
    [root@bogon ~]#

    命令解释:
    通过命令-F参数指定区域分隔符
    [ ,]是正则表达式里面的内容,它表示一个整体,“一个”字符,既空格或者逗号(,),合并在一起,-F “[ ,]”就表示以空格或者逗号(,)为区域分隔符

    第5章

    awk默认就支持的元字符:

    元字符功能示例解释
    ^ 字符串开头 /^chensiqi/或$3~/^chensiqi/ 匹配所有以chensiqi开头的字符串;匹配出所有第三列中以chensiqi开头的
    $ 字符串结尾 /chensiqi$/或$3~/chensiqi$/ 匹配所有以chensiqi结尾的字符串;匹配第三列中以chensiqi结尾的
    .(点) 匹配任意但个字符(包括回车符) /c..l/ 匹配字母c,然后两个任意字符,再以l结尾的行
    * 重复0个或多个前一个字符 /a*cool/ 匹配0个或多个a之后紧跟着cool的行
    + 重复前一个字符一次或多次 /a+b/ 匹配一个或多个a加上字符串b的行
    ? 匹配0个或一个前边的字符 /a?b/ 匹配以字母a或b或c开头的行
    [] 匹配指定字符组内的任一个字符 /^[abc]/ 匹配以字母a或b或c开头的行
    [^] 匹配不在指定字符组内的任一字符 /^[^abc]/ 匹配不以字母a或b或c开头的行
    () 子表达式组合 /(chensiqi)+/ 表示一个或多个cool组合,当有一些字符需要组合时,使用括号括起来
    | 或者的意思 /(chensiqi)|B/ 匹配chensiqi或字母B的行

    awk默认不支持的元字符:(参数--posix)

    元字符功能示例解释
    x{m} x字符重复m次 /cool{5}/ 匹配l字符5次
    x{m,} x字符重复至少m次 /(cool){2,}/ 匹配cool整体,至少2次
    x{m,n} x字符重复至少m次,但不超过n次 /(cool){5,6}/ 匹配cool整体,至少5次,最多6次

    提示:

    • 加括号代表整体匹配,不加那么就匹配前边的一个字符。awk默认不支持这种形式的正则,需要加--posix参数或者--re-interval
    • 正则表达式的运用,默认是在行内查找匹配的字符串,若有匹配则执行action操作,但是有时候仅需要固定的列来匹配指定的正则表达式,比如:我想取/etc/passwd文件中第五列{$5}这一列查找匹配mail字符串的行,这样就需要用另外两个匹配操作符,并且awk里面只有这两个操作符来匹配正则表达式。

    实在1

    [root@bogon ~]# awk -F":" '$0~/^root/' /test/files/awkfile.txt
    root:x:0:0:root:/root:/bin/bash
    [root@bogon ~]# cd /test/files/
    [root@bogon files]# ls
    awkfile.txt  count.txt  ip.txt  test.txt
    [root@bogon files]# awk -F":" '/^root/' awkfile.txt
    root:x:0:0:root:/root:/bin/bash
    [root@bogon files]#

    命令解释

    awk只用正则表达式的时候是默认匹配整行的即‘$0~/^root/’和‘/^root/’是一样的。

    实战2

    匹配其中某一行

     [root@bogon files]# awk -F ":" '$5~/shutdown/' awkfile.txt
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    [root@bogon files]#

    第6章

    文件测试

    [root@bogon files]# cat >>/test/files/reg.txt<<KOF
    > Zhang Dandan    41117397    :250:100:175
    > Zhang Xiaoyu    390320151   :155:90:201
    > Meng  Feixue    80042789    :250:60:50
    > Wu    Waiwai    70271111    :250:80:75
    > Liu   Bingbing  41117483    :250:100:175
    > Wang  Xiaoai    3515064655  :50:95:135
    > Zi    Gege      1986787350  :250:168:200
    > Li    Youjiu    918391635   :175:75:300
    > Lao   Nanhai    918391635   :250:100:175
    > KOF

    说明:

    • 第一列是姓氏
    • 第二列是名字
    • 第一列第二列合起来就是姓名
    • 第三列是对应的ID号码
    • 最后三列是三次捐款数量

     

    2.2.7 awk正则表达式练习题

    练习题1:显示姓Zhang的人的第二次捐款金额及她的名字

    练习题2:显示Xiaoyu的名字和ID号码

    练习题3:显示所有以41开头的ID号码的人的全名和ID号码

    练习题4:显示所有以一个D或X开头的人名全名

    练习题5:显示所有ID号码最后一位数字是1或5的人的全名

    练习题6:显示Xiaoyu的捐款,每个值都有以$开头。如$520$200$135

    练习题7:显示所有人的全名,以姓,名的格式显示,如Meng,Feixue

    练习题1

    示例1:显示姓Zhang的人的第二次捐款金额及她的名字

    [root@bogon files]# awk -F "[ :]+" '$1~/^Zhang/{print $1,$2,$5}' reg.txt
    Zhang Dandan 100
    Zhang Xiaoyu 90
    [root@bogon files]#

    或者

    awk -F "[ :]+" '$1~/^Zhang/{print $2,$(NF-1)}' reg.txt

    说明:

    • -F指定分隔符,现在大家知道了-F即FS也是支持正则表达式的。
    • 【 :】+ 表示连续的空格或冒号
    • -F “【 :】+” 以连续的空格或冒号为分隔符
    • /Zhang/表示条件,整行中包含Dan字符的这个条件。
    • {print $1,$(NF-1)} 表示动作,满足条件后,执行显示第一列($1)和倒数第二列($(NF-1))当然$5也可以。

    注意:
    NF是一行中有多少列,NF-1整行就是倒数第二列。
    $(NF-1)就是取倒数第二列内容。

    练习题二

    练习题2:显示Xiaoyu的名字和ID号码

    [root@bogon files]# awk '/Xiaoyu/{print $1,$3}' reg.txt
    Zhang 390320151
    [root@bogon files]#

    或者

     awk -F "[ :]+" '$2~/^Xiaoyu/{print $1,$3}' reg.txt

    命令说明:
    指定分隔符-F “【:】+”
    $2~/Xiaoyu/表示条件,第二列包含Xiaoyu时候执行对应的动作
    {print $1,$3}表示动作,显示第一列和第三列的内容

    练习三

    练习题3:显示所有以41开头的ID号码的人的全名和ID号码

    [root@bogon files]# awk '$0~/41/' reg.txt
    Zhang Dandan    41117397    :250:100:175
    Liu   Bingbing  41117483    :250:100:175
    [root@bogon files]# awk '$0~/41/{print $1,$2,$3}' reg.txt
    Zhang Dandan 41117397
    Liu Bingbing 41117483
    [root@bogon files]# awk '$3~/41/{print $1,$2,$3}' reg.txt
    Zhang Dandan 41117397
    Liu Bingbing 41117483
    [root@bogon files]#

    练习题4:显示所有以一个D或X开头的人名全名

    [root@bogon files]# awk -F "[ :]+" '$2~/^D|^X/{print $1,$2}' reg.txt
    Zhang Dandan
    Zhang Xiaoyu
    Wang Xiaoai
    [root@bogon files]#

    命令说明:
    -F “【 :】+”指定分隔符
    |表示或,^以...开头

    示例5:显示所有ID号码最后一位数字是1或5的人的全名

    [root@bogon files]# awk '$3~/1$|5$/{print $1,$2}' reg.txt
    Zhang Xiaoyu
    Wu Waiwai
    Wang Xiaoai
    Li Youjiu
    Lao Nanhai
    [root@bogon files]# awk -F"[ :]+" '$3~/1$|5$/{print $1,$2}' reg.txt
    Zhang Xiaoyu
    Wu Waiwai
    Wang Xiaoai
    Li Youjiu
    Lao Nanhai
    [root@bogon files]#

    示例6:显示Xiaoyu的捐款,每个值都有以$开头。如$520$200$135

    [root@bogon files]# awk -F"[ :]+" '$2~/Xiaoyu/{print "$"$4"$"$5"$"$6}' reg.txt
    $155$90$201
    [root@bogon files]#

    示例7:显示所有人的全名,以姓,名的格式显示,如Meng,Feixue

    [root@bogon files]# awk  '{print $1","$2}' reg.txt
    Zhang,Dandan
    Zhang,Xiaoyu
    Meng,Feixue
    Wu,Waiwai
    Liu,Bingbing
    Wang,Xiaoai
    Zi,Gege
    Li,Youjiu
    Lao,Nanhai
    [root@bogon files]#

    实例8 :取出网卡eth0的ip地址

    [root@bogon files]# ip addr |awk -F "[ /]+"  'NR==9{print $3}'
    192.168.1.111
    [root@bogon files]#

    第7章

    正侧扩展

    [root@bogon files]# echo "---===1###2"
    ---===1###2
    [root@bogon files]# echo "---===1###2" |grep "[-=#]"
    ---===1###2
    [root@bogon files]# echo "---===1###2" |grep -o "[-=#]"
    -
    -
    -
    =
    =
    =
    #
    #
    #
    [root@bogon files]#

    awk正则之{} -花括号

    awk中的花括号有些不常用,但是偶尔会用到这里简单介绍。

    示例:取出awkfile中第一列包含一个o或者两个o的行

    [root@bogon files]# awk -F":" '$1~/o{1,2}/' awkfile.txt
    root:x:0:0:root:/root:/bin/bash
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    operator:x:11:0:operator:/root:/sbin/nologin
    [root@bogon files]#

    [root@bogon files]# awk -F: --re-interval '$1~/o{1,2}/' awkfile.txt
    root:x:0:0:root:/root:/bin/bash
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    operator:x:11:0:operator:/root:/sbin/nologin

    2.实例

    取出常用的服务端口

    [root@bogon files]# awk -F "[ /]+" '$1~/^(ssh)$|^(http)$|^(https)$|^(mysql)$|^(ftp)$/{print $1,$2}' /etc/services |sort |uniq
    ftp 21
    http 80
    https 443
    mysql 3306
    ssh 22
    [root@bogon files]#

    • |是或者的意思,正则表达式
    • sort是将输出结果排序
    • uniq是去重复但不标记重复个数
    • uniq -c去重复但标记重复个数

     实例3

    说明:
    条件:从第三列以bin开头字符串的行到第三列以lp开头字符串的行
    动作:显示行号和整行

    [root@bogon files]# awk '/^bin/,NR==5{print NR,$0}' awkfile.txt
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

    示例4

    awk -F":" '$5~/^bin/,/^lp/{print NR,$0}' awkfile.txt
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

    说明:
    条件:从第五列以bin开头的行到以lp开头的行
    动作:显示行号和正航内容
    合起来:从第三列以bin开始的行到以lp开头的行并显示其行号和整行内容

    第九章

    BEGIN 用法

    [root@bogon files]# awk -F":" 'BEGIN{print "username","UID"}{print $1,$3}' awkfile.txt
    username UID   ##这就是输出的表头信息
    root 0
    bin 1
    daemon 2
    adm 3
    lp 4
    sync 5
    shutdown 6
    halt 7
    mail 8
    operator 11
    [root@bogon files]#

    说明:
    要在第一行输出一些username和UID,我们应该想到BEGIN{}这个特殊的条件(模式),因为BEGIN{}在awk读取文件之前执行的。
    所以结果是BEGIN{print "username","UID"},注意print命令里面双引号吃啥吐啥,原样输出。
    然后我们实现了在输出文件内容之前输出“username”和“UID”,下一步输出文件的第一列和第三列即{print $1,$3}
    最后结果就是BEGIN{print "username","UID"}{print $1,$3}

     2/使用BEGIN模块的特殊性质,进行一些测试。

    [root@www files]#简单输出内容: [root@www files]# awk 'BEGIN{print "hello world!"}'
    hello world!
    [root@www files]# #进行计算
    [root@www files]# awk 'BEGIN{print 10/3}'
    3.33333
    [root@www files]# awk 'BEGIN{print 10/3+1}'
    4.33333
    [root@www files]# awk 'BEGIN{print 10/3+1/4*9}'
    5.58333
    [root@www files]# #和变量有关的操作
    [root@www files]# awk 'BEGIN{a=1;b=2;print a,b}'
    1 2
    [root@www files]# awk 'BEGIN{a=1;b=2;print a,b,a+b}'
    1 2 3

    企业案例:统计/etc/servies文件里的空行数量

    思路:
    a)空行通过正则表达式来实现:^$
    b)统计数量:

    • grep -c
    • awk

    方法一:grep

    grep "^$" /etc/services | wc -l
    16
     grep -c "^$" /etc/services
    16
    
    说明:
    grep命令-c表示count计数统计包含^$的行一共有多少。

    方法二:

     awk '/^$/{i++}END{print i}' /etc/services 
    16

    提示:
    使用了awk的技术功能,很常用
    第一步:统计空行个数
    /^$/表示条件,匹配出空行,然后执行{i++}(i++等于i=i+1)即:/^$/{i=i+1}

    我们可以通过/^$/{i=i+1;print i}来查看awk执行过程

    wk '/^$/{i=i+1;print "the value of i is:"i}' /etc/services 
    the value of i is:1
    the value of i is:2
    the value of i is:3
    the value of i is:4
    the value of i is:5
    the value of i is:6
    the value of i is:7
    the value of i is:8
    the value of i is:9
    the value of i is:10
    the value of i is:11
    the value of i is:12
    the value of i is:13
    the value of i is:14
    the value of i is:15
    the value of i is:16

    第二步:输出最后结果

    • 但是我们只想要最后的结果16,不想要过程怎么办?使用END模式输出结果
    • 因为END模式的特殊性质所以很适合输出最终结果

    所以最终结果就是awk '/^$/{i=i+1}END{print "blank lines count:"i}' /etc/services

    awk编程思想:

    1. 先处理,最后再END模块输出
    2. {print NR,$0}body模块处理,处理完毕后
    3. END{print "end of file"}输出一个结果

    企业面试题5:文件count.txt,文件内容是1到100(由seq 100生成),请计算文件每行值加起来的结果(计算1+...+100)

    思路:
    文件每一行都有且只有一个数字,所以我们要让文件的每行内容相加。
    回顾一下上一道题我们用的是i++即i=i+1
    这里我们需要使用到第二个常用的表达式
    i=i+$0

    对比一下,其实只是把上边的1换成了$0

    awk '{i=i+$0}END{print i}' count.txt 
    5050

     

  • 相关阅读:
    SQL语句大全
    网页常用小技巧
    卡通时钟代码
    舒服的颜色2
    静态代码
    Hibernate工作原理
    SQl多表查询优化 高效率SQL语句
    Hibernate API、对象状态、HQL、Criteria
    MySQL 学习笔记
    intramart知识
  • 原文地址:https://www.cnblogs.com/zoulixiang/p/9754777.html
Copyright © 2011-2022 走看看