zoukankan      html  css  js  c++  java
  • Linux文本处理三剑客之awk学习笔记01:前言

    本博文参考的资料来自于骏马金龙的awk教程,该教程在51CTO上也有对应的课程,欢迎大家付费支持。本博文默认读者已经具备了正则表达式基础

    前言

    本博客中使用的示例文件a.txt内容如下。

    ID  name    gender  age  email          phone
    1   Bob     male    28   abc@qq.com     18023394012
    2   Alice   female  24   def@gmail.com  18084925203
    3   Tony    male    21   aaa@163.com    17048792503
    4   Kevin   male    21   bbb@189.com    17023929033
    5   Alex    male    18   ccc@xyz.com    18185904230
    6   Andy    female  22   ddd@139.com    18923902352
    7   Jerry   female  25   exdsa@189.com  18785234906
    8   Peter   male    20   bax@qq.com     17729348758
    9   Steven  female  23   bc@sohu.com    15947893212
    10  Bruce   female  27   bcbd@139.com   13942943905

    读取数据的方式

    在讲解文本处理工具awk之前我们需要先来看一下命令/工具从文件中读取数据的几种方式,大多数方式我们可以使用bash中的read命令来模拟,无法模拟的我们知道其思路也可以。

    1、按字符数量读取。每次根据指定的字符数量来读取数据。

    这里注意不要使用要使用-N而不是-n,这样子才可以将空白字符、换行符等也读入。在echo时使用双引号包裹变量引用可以防止空格压缩,前后使用3个中划线“-”用来显示变量头尾,可以看出变量是否包含空白字符。

    [root@c7-server ~]# read -N 4 char < a.txt 
    [root@c7-server ~]# echo "---$char---"
    ---ID  ---

    2、按字节数量(即数据大小)读取。每次根据指定的字节数量来读取数据。

    3、按分隔符读取。从文件开始处读取数据,遇到分隔符后停止,将读取到的数据保存,下次读取时从分隔符位置后继续读取,每次保存的数据中不会包含分隔符本身。

    输出结果的第3和第4行数据属于同一次读取的数据,之所以换行是因为数据本身包含了换行符。

    [root@c7-server ~]# while read -d "m" chars; do echo "---$chars---"; done < a.txt 
    ---ID  na---
    ---e    gender  age  e---
    ---ail          phone
    1   Bob---
    ---ale    28   abc@qq.co---
    ... ...

    4、按行读取。它可以理解为特殊的按分隔符读取,即分隔符为换行符( )。

    [root@c7-server ~]# while read line; do echo "---$line---"; done < a.txt 
    ---ID  name    gender  age  email          phone---
    ---1   Bob     male    28   abc@qq.com     18023394012---
    ---2   Alice   female  24   def@gmail.com  18084925203---
    ... ...

    5、一次性读取整个所有数据。它既可以理解为按无限大字符/字节数量读取,也可以理解为按文件中不存在的字符作为分隔符读取。

    [root@c7-server ~]# read -N 10000 chars < a.txt 
    [root@c7-server ~]# echo "---$chars---"
    ---ID  name    gender  age  email          phone
    1   Bob     male    28   abc@qq.com     18023394012
    ... ...
    9   Steven  female  23   bc@sohu.com    15947893212
    10  Bruce   female  27   bcbd@139.com   13942943905
    ---
    [root@c7-server ~]# read -d "_" chars < a.txt 
    [root@c7-server ~]# echo "---$chars---"
    ---ID  name    gender  age  email          phone
    1   Bob     male    28   abc@qq.com     18023394012
    ... ...
    9   Steven  female  23   bc@sohu.com    15947893212
    10  Bruce   female  27   bcbd@139.com   13942943905---

    用法入门

    awk 'awk_program' a.txt b.txt a.txt

    a.txt:awk命令所要读取的文件,文件可以一个或者多个,也可以重复。文件数也可以是0个,即从标准输入中获取数据。awk并不会将操作直接作用于文件,仅仅是读取文件数据对其进行操作,不会修改源文件。

    'awk_program':单引号包裹的内容叫做awk代码/命令/程序。awk看似是一个命令,实则是一门编程语言,因此将其命令称之为代码也是合理的。

    awk代码既可以使用单引号包裹,又可以使用双引号,但是在几乎所有情况下都使用单引号。因为在代码中会使用一些诸如“$”这类特殊符号,它既可以被bash解释又可以被awk解释,如果使用双引号那么它们就会被bash解释了,为了将它保留给awk解释所以我们才要使用单引号。

    awk代码中常可见“{...}”符号,这个表示的是代码/语句块,块和块之间使用{}分隔,在CLI中同一个语句块内部的多个语句使用分号“;”分隔。如果将代码写在文件中,在CLI中使用-f选项调用的话,则不需要使用分号“;”分隔块内语句。

    接下来我们来看2个示例。

    [root@c7-server ~]# awk '{print $0}' a.txt 
    ID  name    gender  age  email          phone
    1   Bob     male    28   abc@qq.com     18023394012
    ... ...
    10  Bruce   female  27   bcbd@139.com   13942943905
    [root@c7-server ~]# awk '{print $0}{print "Hello";print "world."}' a.txt 
    ID  name    gender  age  email          phone
    Hello
    world.
    1   Bob     male    28   abc@qq.com     18023394012
    Hello
    world.
    ... ...
    10  Bruce   female  27   bcbd@139.com   13942943905
    Hello
    world.

    在默认情况下,awk按行读取数据,每读取一行就会将整行的内容保存至$0。然后对每一行的数据都执行一次{}代码块中的指令,print指令似于bash的echo命令。因此:

    • 第1条命令的含义:对每一行数据执行print $0指令,即打印每行数据。
    • 第2条命令的含义:对每一行数据执行两个代码块的指令,第一个代码块等同于第1条,第二个代码块有条指令,第一条打印Hello,第二条打印world.。

    BEGIN和END代码块

    上文提到的代码块,是在每次awk读入一行(默认)数据时需要执行的操作,这类代码块我们可以将其称之为main代码块,它们是awk的主体(main)代码。

    除了main代码块以外,awk还支持两种代码块:BEGIN和END。

    awk 'BEGIN{print "I am in the front."}{print "Hello world!"}' a.txt
    awk '{print "Hello world!"}END{print "I am in the back."}' a.txt
    awk 'BEGIN{print "I am in the front."}{print "Hello world!"}END{print "I am in the back."}' a.txt

    萌新建议将上面的命令敲出来看结果感受一下。这次main代码块中我们没有打印整行数据本身(print $0),而是打印与读入数据无关的信息,来证实main代码块的工作机制。

    BEGIN代码块:在读入数据之前就会执行的指令,且仅执行1次。由于这个特性的存在,BEGIN代码块可以不需要读入数据(文件或者STDIN),我们在测试某些awk特性的时候也可以仅使用BEGIN代码块。

    ~]# awk 'BEGIN{print "I need no files and input."}'
    I need no files and input.

    由于是在读入数据之前就会执行,因此在BEGIN代码块中无法正常引用$0变量,和该变量类似的其他赋值方式相同的变量也无法正常引用。强行引用的话会是空字符串。因为这类变量的赋值均需要在有读入数据的情况下。

    END代码块:在所有数据读取并执行完main代码块之后会执行的指令,且仅执行1次。如果有END代码块,那么就必须有读入数据,若没有则必须在STDIN键入Ctrl+d来表示EOF,否则awk命令会阻塞直到遇到EOF。

    [root@c7-server ~]# awk 'END{print "aaaa"}'
    1
    2
    3
    aaaa

    上面的输出结果中,1、2和3是我键入的STDIN,由于没有main代码块因此什么也没有发生(无论是表面上来看还是awk运行内部)。而aaaa则是我键入Ctrl+d后,awk收到EOF,此时awk才执行END代码块的内容。

    END代码块中可以引用$0类的变量,其值与读入数据最后一行(默认)的数据相关。

    [root@c7-server ~]# tail -n 1 a.txt 
    10  Bruce   female  27   bcbd@139.com   13942943905
    [root@c7-server ~]# awk 'END{print $0}' a.txt 
    10  Bruce   female  27   bcbd@139.com   13942943905

    一般来说,为了看起来更舒服,我们一般将BEGIN写在main之前(左侧),END写在main之后(右侧),中间有一个或者多个main。

    代码块中的指令可以为空(即没有,啥也不干)。main代码块为空的话则可以连大括号都省略了。

    awk 'BEGIN{}{}{}{}END{}' ....
    awk 'BEGIN{}END{}' ....

    更新awk

    awk这个工具最早是在1977年由3位大牛所编写,工具名称来源于三位程序员的名字:Alfred Aho、Peter Weinberger和Brian Kernighan。而我们现在在Linux上所使用的awk则是来源于GNU组织所改变的gawk,为了不改变大家的使用习惯,使用awk做了软链接。

    ~]# ls -l $(which awk)
    lrwxrwxrwx 1 root root 30 Dec 13 17:32 /usr/bin/awk -> gawk

    程序包名称为gawk。

    ~]# rpm -qa | grep "awk"
    gawk-4.0.2-4.el7_3.1.x86_64

    教程作者使用的版本是4.2.0,因此为了后续实验的正确性我们需要使用4.2.0版本的awk。作者给出了更新方式。

    wget --no-check-certificate https://mirrors.tuna.tsinghua.edu.cn/gnu/gawk/gawk-4.2.0.tar.gz
    tar xf gawk-4.2.0.tar.gz
    cd gawk-4.2.0/
    ./configure --prefix=/usr/local/gawk4.2 && make && make install
    ln -fs /usr/local/gawk4.2/bin/gawk /usr/bin/awk
    awk --version
    gawk --version

    当我们想使用4.2.0版本的awk的时候直接键入awk命令,想使用4.0.2旧版本的awk时则键入gawk命令。在我撰写本博客的时候,GNU awk官方的documentation已经更新到5.1的了。

  • 相关阅读:
    other备忘
    Mdoelsim10.4怎么脚本单独仿真ISE14.7 IP核
    Vivado怎么使用In system debug(类似于chipscope的东西)
    Vivado如何使用bat脚本一键创建工程
    Vivado中VIO核使用
    FPGA上外挂DDR2&DDR3&MIG IP的使用记录
    Vivado2016旧工程IP移动到新工程
    怎样在ISE14.7中固化FLASH文件
    Quartus13.1全编译出现引脚错误(神级bug)
    自用windows小软件
  • 原文地址:https://www.cnblogs.com/alongdidi/p/awkPreface.html
Copyright © 2011-2022 走看看