美文网首页Shell
【linux命令学习】— awk 命令学习

【linux命令学习】— awk 命令学习

作者: 疯狂的哈丘 | 来源:发表于2018-10-08 22:22 被阅读10次

    本人的CSDN博客地址
    https://blog.csdn.net/u013332124/article/details/82974759

    一、awk 介绍

    awk是linux上一款强大的文本分析工具,它可以将文件逐行的读入,然后用分割符分割开来,再对分割的各个部分进行处理。awk分割的各个部分叫做域,默认的分割符是空格和制表符。可以通过-F来指定分割符。

    awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。

    二、使用姿势

    主要语法

    awk [参数] 'pattern{action}'

    awk的使用看起来比较复杂,但是掌握好它的语法后,其实也很简单。

    和大多数的命令一样,awk可以指定一些参数,也可以不传任何参数。awk具体支持哪些参数读者可以通过man awk查看相关帮助文档。这里就不多做介绍。

    在参数后面跟着一个单引号括起来的执行语句,其中pattern表示过滤规则,支持正则表达式和逻辑表达式。如果pattern涉及多个条件,可以用 &&|| 来关联,分别表示与和或。pattern可以不填,表示不过滤任何数据。

    pattern后面根据一个花括号括起来的真正的执行语句,比如 print $1 表示输出分割后的第一个域。action{}可以有多个语句,以;号隔开。如果缺失action则表示输出一整行的内容。和{print}以及{print $0}效果一样

    使用示例

    假设有一段文本test.txt,有2个用逗号隔开的列,分别表示姓名、年龄。

    jack,18
    nick,24
    joe,19
    hack,19
    

    输出所有人的名字

    awk -F , '{print $1}' test.txt
    

    -F ,表示用逗号作为分割符,之后pattern为空,action则为{print $1}。awk执行后,每一行都会分割成两列,之后输出第一列的数据。其中1则表示第一列的数据, \2则表示第二列的数据,以此类推,$n则表示第n列的数据。要注意的是,$0表示的是这一整行的数据

    输出年龄小于20岁,并且名字中带有ck内容的人(整行正则匹配)

    awk -F , '/ck/ && $2 < 20{print}' test.txt
    

    上面用两个斜杠//围起来的就是正则表达式,awk会对每行进行正则匹配,匹配不上的就不会进行处理。

    由于直接使用//匹配的是整行数据,所以如果我们的需求是要找名字中带有ck内容的人的话,语句就不是很正确。因为如果这一行中刚好有其他字段也包含了ck,那么就可能造成误匹配。那么,怎么就对名字这个字段进行正则匹配呢?

    输出年龄小于20岁,并且名字中带有ck内容的人(就对名字的字段进行匹配)

    awk -F , '$1 ~ /ck/ && $2 < 20{print}' test.txt
    

    $1 ~ //则表示对第一列数据进行正则匹配。

    BEGIN和END关键字

    action里面的语句会对每一行过滤后的数据进行输出,那么,如果我们想在输出的头部和尾部增加一些内容,应该怎么做呢?答案就是使用BEGIN和END关键字。记得一定要大写

    BEGIN后面跟一个语句块{},表示在awk扫描文本前输出一些内容。END用法也一样,在awk扫描文本后输出一些内容。

    awk -F , 'BEGIN {print "name,age"} {print} END {print "end"}' test.txt
    //输出 
    name,age
    jack,18
    nick,24
    joe,19
    hack,19
    end
    

    上面的语句我们可以看到有3个{}语句块,分别表示扫描前语句块扫描文本时使用的语句块扫描后语句块

    内置变量

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

    awk内置了一些变量,我们可以在语句块直接使用 。

    直接输出第2行的数据

    awk -F , 'FNR==2 {print}' test.txt
    

    print和printf的区别

    awk中同时提供了print和printf两种打印输出的函数。

    其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用括起来,参数必须用逗号分隔,不然多个参数之间连在一起会造成混淆。

    printf和c语言中的printf基本一样,可以格式化字符串。

    print输出例子

    awk -F , '{print "name="$1",""age="$2}' test.txt
    

    printf输出例子

    awk -F , '{printf "name=%s,age=%0.2f\n",$1,$2}' test.txt
    
    //输出
    name=jack,age=18.00
    name=nick,age=24.00
    name=joe,age=19.00
    name=hack,age=19.00
    

    通过printf,我们可以将年龄转化成小数点

    三、awk 脚本

    通过 -f scriptfile 来将awk执行语句放到脚本中。我们可以编写一个awk脚本test.awk

    BEGIN {print "name,age"}
    $2 < 20 && /ck/ {print $1}
    END {print "end"}
    

    之后执行

    awk -F , -f test.awk test.txt
    

    等同于执行

    awk -F , 'BEGIN {print "name,age"}  $2 < 20 && /ck/ {print $1} END {print "end"}'
    

    awk脚本也可以这么写

    #!/usr/bin/awk -f
    BEGIN {print "name,age"}
    $2 < 20 && /ck/ {print $1}
    END {print "end"}
    

    之后直接执行该脚本即可

    ./test.awk -F , test.txt
    

    四、awk 编程

    定义变量

    awk语句中可以直接定义变量然后使用

    # 设置count变量,统计一共有多少行
    awk -F , '{count++;print $0} END {print count}' test.txt
    # 设置count变量的初始值为1
    awk -F , 'BEGIN{count=1} {count++;print $0} END {print count}' test.txt
    

    我们可以在BEGIN语句块中设置变量的初始值,如果print要输出一个没有定义过的变量,awk也不会报错,而是输出空字符串。

    条件语句

    awk的条件语句也和C语言基本一样。

    # 如果岁数小于20岁并且名字字段带有ck,输出的岁数就+5,否则就+1
    awk -F , '{if($2<20 && $1 ~ /ck/){print $1,$2+5}else{print $1,$2+1}}' test.txt
    

    上面的语句就是我们常见的if…else,很好理解。

    循环语句

    awk的循环语句也和C语言基本一样。支持while、do/while、for、break、continue这些关键字。

    # 每一行重复输出3次
    awk -F, 'BEGIN{i=0} {while(i<3){print $0;i++};i=0}' test.txt
    awk -F, '{for(i=0;i<3;i++){print $0}}' test.txt
    

    数组

    awk的数组的下标可以是数字或者字母,这和js的map比较像。

    # 输出的过程中,遇到名字是nick的,把它的名字转换成 hello 。最后我们再输出一个world
    awk -F, 'BEGIN{nickname["nick"]="hello";nickname[1]="world"} {if(nickname[$1]!=""){print nickname[$1],$2}else{print $1,$2}} END{print nickname[1]}' test.txt
    

    上面的语句在BEGIN块中定义了nickname的数组,同时使用了两种下标,分别是"nick"和数字1。之后在后面也用到了。

    五、写在结尾

    awk是linux上一款处理文本的神器,以前看到或者要用的时候总是习惯去百度,然后直接抄过来改一点东西,而没有去较系统的学习一下。主要还是被它那看似复杂的语句块吓住,今天在认真看了几篇awk教程后发现其本质也很简单,学习起来其实很快。个人觉的有编程基础的人,差不多半个小时就足以将awk掌握个大概。

    当然,要深入的学习awk肯定不是一件简单的事,本篇博客也只是对awk的语句进行一些简单的介绍,也足以应付我们工作中大部分的需求。如果想深入学习awk的同学可以去官方文档http://www.gnu.org/software/gawk/manual/gawk.html学习看看。

    相关文章

      网友评论

        本文标题:【linux命令学习】— awk 命令学习

        本文链接:https://www.haomeiwen.com/subject/ivrsaftx.html