前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >linux awk指令详解

linux awk指令详解

作者头像
我是李超人
发布2020-08-21 00:53:53
3K0
发布2020-08-21 00:53:53
举报

声明:一下内容均总结自鸟哥私房菜。

sed是对行进行处理,而awk是对列做处理。看下面这个例子: 将上次登录的用户前三行列出来,只显示用户名和IP

代码语言:javascript
复制
[root@localhost ~]# last | awk '{print $1 "\t" $3}' | head -n 3
root    192.168.1.1
root    192.168.1.1
root    192.168.1.1

可以通过awk指令,只将第一列和第三列的内容取出来。awk中默认的分隔符是空格或者tab键,所以有时候取出来的数据类型并不是一致的,可能是你的数据结构有问题。 awk的指令格式通常是这样的:

代码语言:javascript
复制
[root@linux ~]# awk '条件类型 1{动作 1} 条件类型 2{动作 2} ...' filename

其中条件类型可有可无,比如像最上面这个例子,只存在指令不存在条件。注意,awk后续的所有指令都要使用’’单引号扩起来,打印时非变量的部分要使用双引号扩起来。动作必须存放在{}中,变量$1,$2,$3等就表示第一列,第二列,第三列等,而$0比较特殊,它表示一整行。

awk指令执行的顺序是下面这样的: 1. 读入第一行,将第一行存放在$0中,将第一列,第二列等分别存放在,$1, $2…. 等变数当中; 2. 依据 “条件类型” 的限制,判断是否需要进行后面的 “动作”; 3. 做完所有的动作与条件类型; 4. 若还有后续的『行』的数据,则重复上面 1~3 的步骤,直到所有的数据都读完为止。

awk中一些内建变量

变量名称

代表含义

NF

每一行 ($0) 拥有的字段总数

NR

目前 awk 所处理的是『第几行』数据

FS

目前的分隔字符,预设是空格键

例1:获取目前所处理的行数和该行的字段数量

代码语言:javascript
复制
[root@localhost ~]# last | awk '{print $1"\t lines: " NR "\t columns: " NF}'

例2:读取/etc/passwd中的内容,当第三列的值小于10时打印出来

代码语言:javascript
复制
[root@localhost ~]# cat /etc/passwd | awk '{FS=":"} $3<10 {print $1 "\t" $3}'
root:x:0:0:root:/root:/bin/bash 
bin 1
daemon  2
adm 3
lp  4
sync    5
shutdown    6
halt    7
mail    8

在这个例子中,先使用cat /etc/passwd读取文件内容,在作为管道流送到下个指令awk ‘{FS=”:”} $3<10 {print $1 “\t” $3}’处理,在该指令中第一个动作{FS=”:”}将分隔符设置成”:”号,设置判断条件$3<10,如果第三列的值小于10,则执行动作{print $1 “\t” $3},将第一列和第三列的值输出来。但是,可以看到第一行没有正确显示出来,因为在读入第一行的时候,这些变数还是按照预设的空格作为分隔符的。那么怎么再读入第一行时就修改这个预设的分隔符呢?可以使用BEGIN。如下所示:

代码语言:javascript
复制
[root@localhost ~]# cat /etc/passwd | awk 'BEGIN {FS=":"} $3<10 {print $1 "\t" $3}'
root    0
bin 1
daemon  2
adm 3
lp  4
sync    5
shutdown    6
halt    7
mail    8

例3:薪资计算功能 创建一张pay.txt文件,文件中输入内容如下: Name 1st 2nd 3th VBird 23000 24000 25000 DMTsai 21000 20000 23000 Bird2 43000 42000 41000 计算每个人的工资总额,并按格式化输出

代码语言:javascript
复制
[root@localhost ~]# cat pay.txt | awk 'NR==1{printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"total"} \
NR>=2{total=$2+$3+$4;printf"%10s %10d %10d %10d %10.2f\n",$1,$2,$3,$4,total}'
      Name        1st        2nd        3th      total
     VBird      23000      24000      25000   72000.00
    DMTsai      21000      20000      23000   64000.00
     Bird2      43000      42000      41000  126000.00

上面这个指令有几点要说明: 所有的动作,即在{}内的指令,如果存在多个指令,则每个指令建要用”;”来分隔或者按回车来分隔,否则会报错。与bash shell变量不一样,在awk中定义的变量可以直接使用。此外,awk的指令中支持使用if表达式,上面的指令也可以改成下面这样:

代码语言:javascript
复制
[root@localhost ~]# cat pay.txt | awk '{if(NR==1) printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"total"} NR>=2{total=$2+$3+$4;printf "%10s %10d %10d %10d %10.2f\n",$1,$2,$3,$4,total}'
      Name        1st        2nd        3th      total
     VBird      23000      24000      25000   72000.00
    DMTsai      21000      20000      23000   64000.00
     Bird2      43000      42000      41000  126000.00

例4:高级特性,for循环 新建一个reg.dat文件,在文件中输入内容: Mary O.S. Arch. Discrete Steve D.S. Algorithm Arch. Wang Discrete Graphics O.S. Lisa Graphics A.I. Lily Discrete Algorithm 第一行,表示学生名字,二三四行分别表示该学生所选择的课程,下面使用awk结合for循环以及阵列来统计每门课程的选课人数。

代码语言:javascript
复制
[root@localhost ~]# cat reg.dat | awk '{for(i=2;i<=NF;i++) Number[$i]++} END {for(course in Number) printf("%10s %1d\n",course,Number[course])}'
      O.S. 1
    Class1 1
    Class2 1
 Algorithm 1
      D.S. 1
  Graphics 2
  Discrete 2
     Arch. 1

Awk指令中第一个动作是{for(i=2;i<=NF;i++) Number[$i]++},该动作会将课程名称作为index,统计出每节课程所选人数作为相应的值。要注意,在linux中使用一个数组类型不需要声明,所以在上面这个动作中直接就开始使用Number这个数组了,而$i会将一列中的值全部取出来,作为number的index,然后再取出number[index]值做++操作,所以最后得到的number是以课程名称为index,课程的选课人数为value的数组。END表示必须等到所有的值全部遍历完才执行下面的动作。而第二个动作{for(course in Number) printf(“%10s %1d\n”,course,Number[course])}则是遍历该数组number,并将结果输出来。这些都是awk的高级特性,详细可以参考http://linux.vbird.org/linux_basic/0330regularex/awk.pdf

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-02-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档