• Linux学习64 awk使用与实战


    一、回顾:bash脚本编程数组

      1、数组,字符串处理

      2、数组:

        a、数组:declare -a

          index:0-

        b、关联数组:declare -A

      3、字符串处理

        a、切片,查找替换,查找删除,变量赋值

    二、GUN awk

      1、文本处理三剑客:grep,sed,awk

        a、grep,egrep,fgrep:文本过滤工具:pattern

        b、sed:行编辑器

          (1)、模式空间,保持空间

        c、awk:报告生成器,格式化文本输出

        d、AWK:Aho,Weinberger,Kernighan,三个人对应三个字母

          AWK --> New AWK,NAWK 

          GAWK --> GUN AWK

    [root@www application]# which awk
    /usr/bin/awk
    [root@www application]# ls -l /usr/bin/awk 
    lrwxrwxrwx. 1 root root 4 6月   4 2019 /usr/bin/awk -> gawk

      2、awk

        a、pattern scanning and processing language(模式扫描及实现处理的语言)

        b、基本用法:gawk [options] 'program' FILE ...

          (1)、program: PATTERN{ACTION STATEMENTS}

            语句之间用分号分隔

            print,printf

          (2)、选项

            -F:指明输入时用到的字段分隔符;

            -v var=value:自定义变量

      3、awk的使用

        a、我们接下来说一说awk是怎么处理文本的,sed是读取文本到模式空间中在模式空间进行处理,这种实现方式就是实现文本编辑的。我们awk也是从我们对应的文件中一次读取一行文本,这个读取出来的文本怎么处理呢?在读取出来的这一行文本后他首先会将这个文本按照我们的输入分隔符进行切片,把整个行文本按照我们此前指明的输入分隔符切片成N个组成部分,比如默认分隔符是空白字符,那么他就会切割一行文本为N片,并且把每一片在awk内部自动赋予一个内建的变量来进行保存,这个内建变量叫$1,$2,$3....一直到最后一行,awk可以自行你有多少个字段他就有多少个内建变量来保存这些数据。我们可以在切片后然后显示某一段,如果要显示整个内容我们可以用$0来表示。很显然切割成片以后我们还可以对每一片做额外的加工和处理。当我们对文件中的每一行做了加工切片以后,我们还可以额外做一些条件性的过滤。

          (1)、比如我们切片以后就在每一行的第二片判断它是否在某一个数值范围内,如果在某一数字范围内,我们就把这一行的第四个字段显示出来,这就是条件判断的应用

          (2)、我们还可以对这一行中的每一个片段挨个做类似加工,即我们可以对这一行的每一个片段做循环,然后对每一个片段做加工处理,注意,awk的循环功能不是在行间循环的,因为awk本身就可以遍历文件。但是awk依然有循环的功能,主要是在字段间完成遍历操作的,因为一个行有n个字段,我们要逐字段处理的话我们就必须在字段间完成循环机制才行。

        b、相应的使用方式

          (1)、基本用法

    [root@www ~]# tail -3 /etc/fstab |awk '{print $1,$4}'
    /dev/mapper/centos-root defaults
    UUID=fd514a18-84be-4460-8130-706b3ec88673 defaults
    /dev/mapper/centos-swap defaults

      4、awk用法

        a、常用输出命令

          (1)、print: 使用方式为 print item1,item2

            要点:

            1)、逗号分隔符

            2)、输出的各item可以是字符串,也可以是数值,当前记录的字段,变量或awk的表达式

    [root@www ~]# tail -3 /etc/fstab |awk '{print "hello",$1,$4,6}'
    hello /dev/mapper/centos-root defaults 6
    hello UUID=fd514a18-84be-4460-8130-706b3ec88673 defaults 6
    hello /dev/mapper/centos-swap defaults 6

            3)、如果省略item,相当于print $0,即打印整行字符

        b、变量

          (1)、内建变量

            1)、FS:input field seperator(输入字段分隔符),即我们以哪个字段做分隔符,默认为空白字符,如果我们要改变其值,我们只需要在命令行中使用-v选项指明变量名给其赋一个新值就可以。或者也可以使用-F选项效果也是一样的

    [root@www ~]# awk -v FS=':' '{print $1}' /etc/passwd |tail -2
    tss
    geoclue
    [root@www ~]# awk -F ':' '{print $1}' /etc/passwd |tail -2
    tss
    geoclue

            2)、OFS:output field seperator(输出字段分隔符),即输出的字段用什么分隔,默认为空白字符,如果我们要改变其值,我们只需要在命令行中使用-v选项指明变量名给其赋一个新值就可以

    [root@www ~]# awk -v FS=':' -v OFS='#' '{print $1,$2,$3}' /etc/passwd|tail -2
    tss#x#59
    geoclue#x#994

            3)、RS:input record seperator,输入的换行符。现在我们把空格作为换行符,即某一行中有空白的话空白后就作为新行出现

    [root@www ~]# awk -v RS=' ' '{print $1}' /etc/passwd

            4)、ORS:output record seperator,输出时的换行符

    [root@www ~]# awk -v ORS='#' '{print $1}' /etc/passwd

            5)、NF:number of field:字段数量,自动保存在一个叫NF的内建变量中。比如我们现在要打印最后四行的字段数量

    [root@www ~]# awk '{print NF}' /etc/passwd |tail -4
    1
    1
    11
    3

              如果要打印最后一行的字段,可以使用$NF

    [root@www ~]# awk -v FS=':' '{print $NF}' /etc/passwd |tail -4
    /bin/bash
    /bin/bash
    /sbin/nologin
    /sbin/nologin

            6)、NR:number of record,行数;即可以显示文件有多少行

    [root@www ~]# awk '{print NR}' /etc/passwd 
    1
    2
    3
    4
    ...

            7)、FNR:file number of record,各文件分别计数。如果用NR变量后面跟多个文件名则会统一计数,即所有行号一起统计,如果用FNR变量后面跟多个文件则第一个文件行号统计完了又开始统计第二个文件的行号

    [root@www ~]# awk '{print FNR}' /etc/fstab /etc/issue
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    1
    2
    3

            8)、FILENAME:当前正在处理的文件的文件名,如果我们有多行的话那么每一个行都会显示一次文件名

    [root@www ~]# awk '{print FILENAME}'  /etc/issue
    /etc/issue
    /etc/issue
    /etc/issue

            9)、ARGC:命令行参数的个数

    [root@www ~]# awk '{print ARGC}'  /etc/issue /etc/fstab 
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3
    3

              也可以使用BEGIN显示一行

    [root@www ~]# awk 'BEGIN {print ARGC}'  /etc/issue /etc/fstab 
    3

            10)、ARGV:数组,保存的是命令行所给定的各参数

    [root@www ~]# awk 'BEGIN {print ARGV[0]}'  /etc/issue /etc/fstab 
    awk
    [root@www ~]# awk 'BEGIN {print ARGV[1]}'  /etc/issue /etc/fstab 
    /etc/issue
    [root@www ~]# awk 'BEGIN {print ARGV[2]}'  /etc/issue /etc/fstab 
    /etc/fstab

          (2)、自定义变量(如果不对文件做处理直接使用BEGIN模式即可)

            1)、-v var=value

              变量名区分字符大小写。

    [root@www ~]# awk -v test='hello gawk' 'BEGIN {print test}'
    hello gawk

            2)、在program中直接定义

    [root@www ~]# awk 'BEGIN {test="hello gawk";print test}'
    hello gawk

        c、printf命令:格式化输出命令  printf FORMAT,item1,item2,...

          (1)、FORMAT必须给出

          (2)、不会自动换行,需要显示给出换行控制符,

          (3)、FORMAT中需要分别为后面的每个item指定一个格式化符合

          (4)、格式符

            %c:显示字符的ASCII码

            %d,%i:显示十进制整数

            %e,%E:科学计数法数值显示

            %f:显示为浮点数

            %g,%G:以科学计数法或浮点形式显示数值

            %s:显示字符串

            %u:无符号整数

            %%:显示%自身

              现在我们来显示我们/etc/passwd中的每一行的用户

    [root@www ~]# awk -F: '{printf "%s",$1}' /etc/passwd
    rootbindaemonadmlpsyncshutdownhaltmailoperatorgamesftpnobodysystemd-networkdbuspolkitdapachelibstoragemgmtabrtrpcpostfixntpchronysshdtcpdumptestusernginxredistomcatcentosgentooopenstackmogi
    lefsarchlinuxmoosefsmytestnovauser1user3bashbashernologintestbashuser2zhangsantssgeoclue[root@www ~]#

              他的意思是将我们的$1套到%s上以字符串形式进行显示,并且默认不会加换行符,如果我们要加控制符则需要使用

    [root@www ~]# awk -F: '{printf "%s
    ",$1}' /etc/passwd
    root
    bin
    daemon
    ....

              我们还可以加相应的字符串

    [root@www ~]# awk -F: '{printf "username: %s
    ",$1}' /etc/passwd
    username: root
    username: bin
    username: daemon
    ...
    [root@www ~]# awk -F: '{printf "username: %s,UID: %d
    ",$1,$3}' /etc/passwd
    username: root,UID: 0
    username: bin,UID: 1
    username: daemon,UID: 2
    ...

          (5)、修饰符

            #[.#]:第一个数字用来控制显示的宽度,第二个数字表示小数点后的精度,比如%3.1f

            现在我们将第一个参数固定15个字符的宽度(默认会右对齐)

    [root@www ~]# awk -F: '{printf "username: %15s,UID: %d
    ",$1,$3}' /etc/passwd
    username:            root,UID: 0
    username:             bin,UID: 1
    username:          daemon,UID: 2
    ...

            我们也可以让其左对齐显示,只需要写成%-15s即可

    [root@www ~]# awk -F: '{printf "username: %-15s,UID: %d
    ",$1,$3}' /etc/passwd
    username: root           ,UID: 0
    username: bin            ,UID: 1
    username: daemon         ,UID: 2
    ...

            我们也可以使用+显示数值的符号,即正负号,比如%+15s

        d、操作符

          (1)、算术操作符

            x+y,x-y,x*y,x/y,x^y,x%y

            -x

            +x:转换为数值

          (2)、字符串操作符:没有符号的操作符,表示字符串连接

          (3)、赋值操作符

            =,+=,-=,*=,/=,%=,^=

          (4)、比较操作符

            >,>=,<,<=,!=,==

          (5)、模式匹配符

            ~

            !~

          (6)、逻辑操作符

            &&

            ||

            !

          (7)、函数调用

            function_name(argu1,argu2,...)

          (8)、条件表达式:

            selector?if-true-expression:if-false-expression(selector这个条件表达式为真则执行if-true-expression这个语句,如果为假则执行if-false-expression这个语句)

    [root@www ~]# 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

        e、PATTERN:我们说过在awk用法gawk [options] 'program' FILE ...中 program是由PATTERN{ACTION STATEMENTS}组成,我们现在来介绍一下PATTERN。他可以理解为类似的地址定界符

          (1)、empty(空):空模式,匹配每一行

          (2)、/regular expression/:仅处理能够被此处的模式匹配到的行

            我们来处理UUID的行

    [root@www ~]# awk '/^UUID/{print $1}' /etc/fstab 
    UUID=fd514a18-84be-4460-8130-706b3ec88673

            我们来处理UUID以外的行

    [root@www ~]# awk '!/^UUID/{print $1}' /etc/fstab

          (3)、relational expression:关系表达式:结果有“真”有“假”;结果为“真”才会被处理

            1)、“真”:结果为非0值,非空字符串

    [root@www ~]# awk -F: '$3>1000{print $1,$3}' /etc/passwd
    testuser 5000
    centos 5002
    gentoo 5003
    openstack 3000
    mogilefs 5004
    archlinux 5005
    moosefs 5006
    mytest 5007
    nova 5009
    user1 5010
    user3 5011
    bash 5012
    basher 5013
    nologin 5015
    testbash 5016
    user2 5017
    zhangsan 5018

              显示其默认shell为bash的用户

    [root@www ~]# awk -F: '$NF=="/bin/bash"{print $1,$NF}' /etc/passwd
    root /bin/bash
    centos /bin/bash
    gentoo /bin/bash
    openstack /bin/bash
    mogilefs /bin/bash
    archlinux /bin/bash
    moosefs /bin/bash
    mytest /bin/bash
    bash /bin/bash
    basher /bin/bash
    testbash /bin/bash
    user2 /bin/bash
    zhangsan /bin/bash

              我们也可以通过模式匹配来实现,即只要最后一个字段是以bash结尾的就将其处理

    [root@www ~]# awk -F: '$NF~/bash$/{print $1,$NF}' /etc/passwd
    root /bin/bash
    centos /bin/bash
    gentoo /bin/bash
    openstack /bin/bash
    mogilefs /bin/bash
    archlinux /bin/bash
    moosefs /bin/bash
    mytest /bin/bash
    bash /bin/bash
    basher /bin/bash
    testbash /bin/bash
    user2 /bin/bash
    zhangsan /bin/bash

          (4)、line ranges:行范围

            1)、startline,endline(awk不支持直接给出数字的格式),要基于行模式进行定界的话需要基于NR来判断

    [root@www ~]# awk -F: '(NR>=2&&NR<=5){print $1}' /etc/passwd
    bin
    daemon
    adm
    lp

            2)、/pat1/,/pat2/

    [root@www ~]# awk -F: '/^root/,/^sync/{print $1,$3}' /etc/passwd 
    root 0
    bin 1
    daemon 2
    adm 3
    lp 4
    sync 5

           (5)、BEGIN/END模式。awk有一种内部功能,就是他能自动遍历文件的每一行然后对每一行我们做出处理,而如果恰好我们的action没有对行内容做出任何处理,对于每一行他也会显示一个字符串出来,如果我们期望在处理文件开始之前就做一次操作,等文件所有的行都处理结束了再做一次操作就可以使用BEGIN/END模式。

            1)、BEGIN{}:仅在开始处理文件中的文件之前执行一次

              我们现在来显示一个用户的用户名和ID号加表头进行显示

    [root@www ~]# awk -F: 'BEGIN{print "username        uid   
    -------------------"}'
    username        uid   
    -------------------
    [root@www ~]# awk -F: 'BEGIN{print "username        uid   
    -------------------"}{print $1,$3}' /etc/passwd
    username        uid   
    -------------------
    root 0
    bin 1
    daemon 2
    ...

            2)、END{}:仅在文本处理完成之后命令结束之前执行一次 

    [root@www ~]# awk -F: 'BEGIN{print "username        uid   
    -------------------"}{print $1,$3}END{print "====================
     end"}' /etc/passwd
    username        uid   
    -------------------
    root 0
    bin 1
    daemon 2
    ...
    ====================
     end

        f、常用的action

          (1)、Expressions,比如谁大于谁谁小于谁

          (2)、Control statements(控制语句):if,while等

          (3)、Compound statements:组合语句

          (4)、input statements:输入语句

          (5)、output statements:输出语句

        g、控制语句

          if(condition){statements}

          if(condition){statements} else {statements}

          while(condition){statements}

          do {statements} while(condition)

          for(expr1;expr2;expr3){statements}

          break

          continue

          delete array[index]

          delete array

          exit

          { statements }

  • 相关阅读:
    时间处理得到UTC时间
    java数据同步陷阱
    360公司2016笔试题
    YTU 1439: 2.4.5 Fractions to Decimals 分数化小数
    YTU 2422: C语言习题 n个数逆序
    YTU 2421: C语言习题 矩形法求定积分
    YTU 2427: C语言习题 整数排序
    YTU 2832: 使用指针访问数组元素--程序填空
    YTU 1050: 写一个函数,使给定的一个二维数组(3×3)转置,即行列互换
    HDU 1069:Monkey and Banana
  • 原文地址:https://www.cnblogs.com/Presley-lpc/p/12655003.html
Copyright © 2020-2023  润新知