shell 脚本之 awk

89 阅读4分钟

什么是awk

awk是一个报告生成器,格式化文本输出。在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,默认以空格或tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。

awk语法

awk [选项] '命令' 文件名(推荐)

  • -F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
  • -v var=value 变量赋值

命令可以由三部分组成

  • BEGIN语句块
  • 模式匹配的通用语句块
  • END语句块

awk 常见的内置变量

1.FS 指定每行文本的字段分隔符,缺省默认为空格或制表符(tab)。与 “-F”作用相同 -v "FS=:"

awk -v FS=':' '{print $1FS$3}' /etc/passwd
#此处FS 相当于于变量  -v 变量赋值  相当于 指定: 为分隔符  

2.OFS 输出时的分隔符

awk -F':' -v OFS='==' '{print $1,$3}' /etc/passwd
root==0
bin==1
daemon==2
adm==3
lp==4

3.RS 行分隔符。awk从文件上读取资料时,将根据RS的定义就把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是\n

echo $PATH | awk -v RS=':' '{print $0}'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin

4.$n当前处理行的第n个字段(第n列)

5.NR当前处理的行的行号(序数)

可以取某一行

 awk 'NR==1{print $0}' /etc/passwd   #读取第一行
root:x:0:0:root:/root:/bin/bash

6.NF当前处理的行的字段个数

#例如取df命令显示的最后一列
df | awk '{print ($NF)}'
## 打印1到10行的内容
 awk 'NR>=1 && NR<=10{print NR,$0}' /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator:x:11:0:operator:/root:/sbin/nologin

uid大于1000 的用户

awk -F: '$3>1000{print NR,$0}' /etc/passwd
29 nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin

8.%0当前处理的行的整行内容

正则表达和动作

/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来

line ranges:行范围

算术操作符
x+y, x-y, x*y, x/y, x^y, x%y
-x:转换为负数
+x:将字符串转换为数值
比较操作符:
==, !=, >, >=, <, <=
#####逻辑
与:&&,并且关系
或:||,或者关系
非:!,取反
模式匹配符:
~ 左边是否和右边匹配,包含关系
!~ 是否不匹配

例子

要求打印偶数行
 
awk -F: 'NR % 2 == 0{print $0}' /etc/passwd
 
解析:
 
NR  :全部行号 除以 2 == 零的 零等于余数

条件判断

用法

awk 选项 '模式 {actions}'
条件判断写在 actions里

if语句:awk的if语句也分为单分支、双分支和多分支
单分支为if(判断条件){执行语句}
双分支为if(判断条件){执行语句}else{执行语句}
多分支为if(判断条件){执行语句}else if(判断条件){执行语句}else if(判断条件){执行语句}else if(判断条件){执行语句 

for 循环

用法

for(expr1;expr2;expr3) {statement;…}
for(variable assignment;condition;iteration process) {for-body}
for(var in array) {for-body}



 awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
5050

计算

awk 'BEGIN{x=10;print x}'  //如果不用引号awk就当作一个变量来输出了,所以不需要加$了

awk 'BEGIN{print x+1}'    //不指定初始值,初始值就为0,如果是字符串,则默认为空
1
[root@localhost ~]# awk 'BEGIN{print 2.5+3.5}'   //小数也可以运算
6
[root@localhost ~]# awk 'BEGIN{print 2-1}'
1
[root@localhost ~]# awk 'BEGIN{print 3*4}'
12
[root@localhost ~]# awk 'BEGIN{print 3**2}'
9

awk数组

awk数组特性:

  • awk的数组是关联数组(即key/value方式的hash数据结构),索引下标可为数值(甚至是负数、小数等),也可为字符串 1. 在内部,awk数组的索引全都是字符串,即使是数值索引在使用时内部也会转换成字符串 2. awk的数组元素的顺序和元素插入时的顺序很可能是不相同的
  • awk数组支持数组的数组

访问、赋值数组元素


arr[idx] = value
索引可以是整数、负数、0、小数、字符串。如果是数值索引,会按照CONVFMT变量指定的格式先转换成字符串

awk 'BEGIN{a[1]="zhangsan";print a[1]}'

数组遍历

格式

for(var in array) {for-body}

awk 'BEGIN{students[1]="zhaizong";students[2]="hezong";students[3]="haizong";for(x in students){print x":"students[x]}}'

将下标转换成  字母
a
aa 后就会不确定

案例

1.提取下面的字段中的 IP地址和时间

58.87.87.99 - - [09/Jun/2020:03:42:43 +0800] "POST /wp-cron.php?doing_wp_cron=1591645363.2316548824310302734375 HTTP/1.1" ""sendfileon

128.14.209.154 - - [09/Jun/2020:03:42:43 +0800] "GET / HTTP/1.1" ""sendfileon

64.90.40.100 - - [09/Jun/2020:03:43:11 +0800] "GET /wp-login.php HTTP/1.1"""sendfileo

使用awk对日志内容格式化输出,1和4 字段 image.png

分割 [ image.png

2.提取host.txt主机名后再放回host.txt文件 >>

1 www.kgc.com 2 mail.kgc.com 3 ftp.kgc.com 4 linux.kgc.com 5 blog.kgc.com

使用awk的示例:

	awk '{print $2}' host.txt >> host.txt

这个命令假设主机名总是在第二个字段(由空白字符分隔)。

image.png