shell中awk命令的使用总结

借鉴别人写的很好的文章:
https://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858470.html
https://www.cnblogs.com/ginvip/p/6352157.html

awk是文本文件的处理工具,主要是进行过滤和搜索,对文件文件的内容通过换行符进行分隔,作为一条记录,,然后将每一条记录默认是以空格为分割符来划分为分隔域,第一个域是$1,第二个是$2,依次类推,其中$0表示整个域,然后对分隔后的数据一条一条的处理,这里和sed进行区分,sed是默认以换行符为分隔符。
语法:
awk ‘{pattern + action}’ {filenames}
这里的action可以有多条语句,多条语句之间用;分隔开,后面会介绍。
eg:

awk -F: 'BEGIN{count=0}{count+=1;print $0}END{printf('count:%s',count)}'

可以看到{count+=1;print $0}中有两个语句,两个语句之间使用;进行分割开来;

第一种用法:

cat /etc/passwd |awk  -F ':'  'BEGIN {print "name,shell"}  {print $1","$7} END {print "blue,/bin/nosh"}'
name,shell
root,/bin/bash
daemon,/bin/sh
bin,/bin/sh
sys,/bin/sh
....
blue,/bin/nosh

awk工作流程是:先执行BEGIN,执行完之后,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0则表示所有域, 1 表 示 第 一 个 域 , 1表示第一个域, 1,n表示第n个域,随后开始执行模式所对应的动作action。接着开始读入第二条记录······直到所有的记录都读完,最后执行END操作。
第二种用法:只有action的
cat /etc/passwd | awk ‘{print $1}’
其中’{print $1}'是action的内容

第三种:只有匹配模式pattern的,匹配之后直接输出:

[root@uc201 ~]# cat /etc/passwd | awk '/root/'
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

第四种:awk + pattern + action

[root@uc201 ~]# cat  /etc/passwd | awk -F: '/root/{print $7}'
/bin/bash
/sbin/nologin

上面的命令大意:匹配有root的行,并将行按照:进行分隔域,分隔之后执行actiion:打印$7。
上面的选项分隔域-F:和-F ":"两种写法都可以。

awk中提供了打印的两个函数,print和printf,print 后面可以根变量,字符串,数值,变量之间可以用逗号但是,表示的是空格,字符串必须用双引号括起来。printf和c语言中一样,支持格式化字符串,如下:

[root@uc201 ~]# awk -F: '{printf("%10s%30s\n",$1,$7)}' /etc/passwd
      root                     /bin/bash
       bin                 /sbin/nologin
    daemon                 /sbin/nologin
       adm                 /sbin/nologin
        lp                 /sbin/nologin
      sync                     /bin/sync
  shutdown                /sbin/shutdown
      halt                    /sbin/halt
      mail                 /sbin/nologin
  operator                 /sbin/nologin
     games                 /sbin/nologin
[root@uc201 ~]# awk -F: '{printf("%10s,%30s\n",$1,$7)}' /etc/passwd
      root,                     /bin/bash
       bin,                 /sbin/nologin
    daemon,                 /sbin/nologin
       adm,                 /sbin/nologin
        lp,                 /sbin/nologin

print的用法:

[root@uc201 ~]# awk -F: '{print $1,$7}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin

下面来详细介绍AWK编程:

一、变量
和其他编程语言一样,awk离不开变量,变量分为内置变量和用户自定义变量。内置变量有特殊意义,如下:
awk有内置变量,还可以自定义变量,其中内置变量如下:
在这里插入图片描述

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

使用:

[root@uc201 ~]# awk  -F ':'  '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin
filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin
filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin
filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

用户自定义变量:

[root@uc201 ~]# awk -F: 'BEGIN{count=0} /root/{count++;print $1} END{printf("count is:%8s\n",count)}' /etc/passwd
root
operator
count is:       2

也可以没有BEGIN对count进行初始化,默认就是0,建议初始化。

再给个例子,里面涉及了计算:

[root@uc201 ~]# ll | awk 'BEGIN{size=0} {size=size+$5} END{print "total size:"size/1024/1024"M" }'
total size:935.212M

这里注意的是:print 后面要是打印字符串的话,需要双引号,变量和双引号之间可以不用空格,如下,单引号会报语法错误。

[root@uc201 ~]# ll | awk '{print ':'$1}'
awk: cmd. line:1: {print :$1}
awk: cmd. line:1:        ^ syntax error
[root@uc201 ~]#
[root@uc201 ~]#
[root@uc201 ~]# ll | awk '{print ":"$1}'
:总用量
:-rw-r--r--.
:-rw-------.
:-r--r--r--.

awk中有变量,那就离不开变量的对变量的运算,下图给出了变量的运算符:包括赋值运算符、逻辑运算符、关系运算符、算数运算符等
在这里插入图片描述
awk支持正则,如下:
在这里插入图片描述

有了变量,那么下一步就是语句了,awk也支持条件语句.
来讲下数组吧:
awk中也有数组的概念,数据的索引可以是数字和字母,和c语言就不太一样了,c语言中的索引只能是数字,awk中数组的存储是按照key/value这样的键值对来存储的,感觉和python中的字典有点像,这里不是按照顺序存储的,所以打印出来显示的话也不是每次顺序都一样,这其实就和字典是一样的了,python中的字典每次打印的话顺序也不是固定的。
举个例子:

netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}'

输出结果

ESTABLISHED 1
LISTEN 20

下面来介绍字符串:这里一定要强调下,字符串是双引号,不能用单引号,不然awk会解析为空白:
例如下面这样:

echo "" | awk 'BEGIN{city[1]='hefei';city[2]='hangzhou'}END{for(i in city)print i,city[i]}

上面的输出结果是:

1
2

我就纳闷了,为啥数组内容没有打印出来,原来是前面的赋值的时候不能用单引号。后来改成下面这样就OK了。

echo "" | awk 'BEGIN{city[1]="hefei";city[2]="hangzhou"}END{for(i in city)print i,city[i]}

运行结果:

1 hefei
2 hangzhou

下图是字符串常用的函数:
在这里插入图片描述
在这里插入图片描述

二、结构化语句
①条件语句
if else语句在awk中的应用:
下面是if else的语法

if (expression) {
    statement;
    statement;
    ... ...
}

if (expression) {
    statement;
} else {
    statement2;
}

if (expression) {
    statement1;
} else if (expression1) {
    statement2;
} else {
    statement3;
}

上面的语句用在awk的action中,直接放进去,当做一个命令。
如下;

[root@uc201 ~]# ll | awk '{if($5<4096){size=size+$5};print $5} END{printf("total size = %s\n",size)}'

76
12232
793
2535
170
980215078
12754
396776
19
total size = 3593

②循环语句
循环语句在awk中应用:
支持while、do/while、for、break、continue,这些关键字的语义和C语言中的语义完全相同。和上面的if一样,都把它当成一个语句就行了,放的位置就是{}这个里面。

[root@uc201 ~]# awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;} END{for (i=0;i<count;i++){printf("%d %10s\n",i,name[i])}}' /etc/passwd    
0       root
1        bin
2     daemon
3        adm
4         lp
5       sync
6   shutdown
7       halt
8       mail
9   operator
10      games
11        ftp
12     nobody
13 systemd-network
14       dbus
15    polkitd
16    unbound
17 libstoragemgmt
18        rpc
19    gluster
20   saslauth
21       abrt
22    postfix
23       qemu
24      radvd
25    rpcuser
26  nfsnobody
27        tss
28       sshd
29 openvswitch
30        ntp
31     chrony
32      admin
33       etcd

其实用起来很简单,就是遇到awk命令,先对文本内容进行按照换行符进行分割成一个一个记录,接着读取记录,然后看awk后面有没有设置分割域,有的话,就使用设置的作为分割域,没有就按照默认的空格为分割域,然后对每个分割域执行操作,如何操作呢,需要看是不是有匹配模式的语句,没有的话,就全部匹配,有的话按照设置的进行匹配,可以是正则表达式进行匹配,匹配之后,对匹配的内容进行操作,操作的内容就是一些命令,包裹在{}中,可以有多个命令,命令和命令之间用;分割开,一条一条从前往后之后执行完{}中的命令之后,然后对第二个记录再按照匹配,执行命令,直到最后所有的记录都执行完。
如果在匹配和命令之前和之后还有BEGIN和END,那就第一次执行第一条记录前执行BEGIN中的内容,最后执行完最后一条记录之后,执行END后面的内容,就结束了。

之前我怎么都没懂,现在回过头来好像没那么难。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

如梦@_@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值