Shell语言基本语法总结(5)文本处理之awk

十、文本处理之awk

10.1、awk简介

  • AWK 是一种处理文本文件的语言,类似c语言,一个强大的文本分析工具。能用简短的程序处理标准输入或文件、数据排序、计算以及生成报表等等。
  • awk 处理的工作方式与数据库类似,支持对记录和字段处理,这也是 grep 和 sed 不能实现的。在 awk 中,缺省的情况下将文本文件中的一行视为一个记录,逐行放到内存中处理,而将一行中的某一部分作为记录中的一个字段。用 1,2,3…数字的方式顺序的表示行(记录)中的不同字段。用$后跟数字,引用对应的字段,以逗号分隔,0 表示整个行。
复杂用法 
awk ' BEGIN { actions }     
awk_pattern1 { actions }
............
awk_patternN { actions }
END { actions }
' inputfile

简单用法: awk [option] ’pattern {action}‘ inputfile 
  • 执行流程:
    • 1、如果BEGIN 区块存在,awk执行它指定的actions;
    • 2、awk从输入文件中读取一行,读入的记录按照指定分隔符分割成字段,将第1个字段放入变量$1中,第2个字段放入$2,以此类推。$0表示整条记录;
    • 3、把当前输入记录依次与每一个awk_pattern比较,如果相匹配,就执行对应的actions;如果不匹配,就跳过对应的actions,直到比较完所有awk_pattern;
    • 4、当一条记录比较完所有awk_pattern后,awk读取下一行,继续重复步骤2和3,这个过程一直持续,直到读取到文件最后一行;
    • 5、当awk读完所有的输入行后,如果存在END,就执行相应的actions。
  • 其中iputfile可以是多于一个文件的文件列表,awk将按顺序处理列表中的每个文件。awk会先对输入文件执行完所有的action后再处理下一个文件。

在这里插入图片描述

10.2、行与列

名词awk叫法说明
记录 record行与行间默认回车分割
字段,域 field列与列间默认空格分割

10.2.1、取行

awk模式说明
NR==1第一行
NR>=1&&NR<=5&&并 取第1—5行
NR==1|NR==4||或 第1行或第4行
/内容/含指定内容的行
/内容1/,/内容2/范围查询
更多符号==;<;>;!=;
[hadoop1@hadoop1 test]$ cat s.txt
cxy,male,19,stu
zzf,female,20,actor
zjm,female,22,actor
ycy,female,23,star
cxl,male,24,stu
bl,female,26,star
[hadoop1@hadoop1 test]$ awk 'NR==2' s.txt
zzf,female,20,actor
[hadoop1@hadoop1 test]$ awk 'NR>=2&&NR<=5' s.txt
zzf,female,20,actor
zjm,female,22,actor
ycy,female,23,star
cxl,male,24,stu
[hadoop1@hadoop1 test]$ awk 'NR==1||NR==4' s.txt
cxy,male,19,stu
ycy,female,23,star
[hadoop1@hadoop1 test]$ awk '/20/' s.txt
zzf,female,20,actor
[hadoop1@hadoop1 test]$ awk '/20/,/24/' s.txt
zzf,female,20,actor
zjm,female,22,actor
ycy,female,23,star
cxl,male,24,stu

10.2.2、取列

符号解释
$n取出第n列
$0取出整行
-F指定分隔符 指定每列结束标记(默认空格)
NF每行有多少列,$NF代表最后一列
FS输入分隔符;-v FS 等同于 -F ; ;如 -F, 或 -v FS=“,” 指定输入分隔符为,
OFS输出分隔符;-v OFS;如 -v OFS=“:” 指定分隔符为 :
# 输出第一列 未指定分隔符
[hadoop1@hadoop1 test]$ awk '{print $1}' s.txt
cxy,male,19,stu
zzf,female,20,actor
zjm,female,22,actor
ycy,female,23,star
cxl,male,24,stu
bl,female,26,star
# 输出第一列 指定分割符,
[hadoop1@hadoop1 test]$ awk -F, '{print $1}' s.txt
cxy
zzf
zjm
ycy
cxl
bl
# 输出第1列、第三列和最后一列 
[hadoop1@hadoop1 test]$ awk -F, '{print $1,$3,$NF}' s.txt
cxy 19 stu
zzf 20 actor
zjm 22 actor
ycy 23 star
cxl 24 stu
bl 26 star
# 输出第1列、第三列和最后一列  输出以 : 为分割符
[hadoop1@hadoop1 test]$ awk -F, -v OFS=":" '{print $1,$3,$NF}' s.txt
cxy:19:stu
zzf:20:actor
zjm:22:actor
ycy:23:star
cxl:24:stu
bl:26:star
  • 同时取行去列:取出ip地址
[hadoop1@hadoop1 test]$ ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.101  netmask 255.255.255.255  broadcast 192.168.1.101
        inet6 fd15:4ba5:5a2b:1008:3f68:66f9:e915:7651  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::c4b6:e442:1b5d:d35d  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:a9:1e:30  txqueuelen 1000  (Ethernet)
        RX packets 1993  bytes 215005 (209.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2140  bytes 224625 (219.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# ip地址 位于第二行第二列 默认空格分割
[hadoop1@hadoop1 test]$ ifconfig ens33 |awk 'NR==2 {print $2}'
192.168.1.101

10.3、模式匹配

  • awk简单用法:awk [option] ’pattern {action}‘ inputfile
  • 比较符号:>;<;<=;>=;==;!=; (参考上面10.2)
  • 正则表达式
  • 范围查询
  • 特殊条件

10.3.1、awk正则表达式

awk正则解释
//支持扩展正则
~包含
!~不包含
^某一列的开头 如:$3~/^2/ 第3列以2开头的行
$某一列的结尾 如:$3~/0$/ 第3列以0结尾的行
^$某一列为空行 如: $3~/^$/ 第3列为空的行
[hadoop1@hadoop1 test]$ cat s.txt
cxy,male,19,stu
zzf,female,20,actor
zjm,female,22,actor
ycy,female,23,star
cxl,male,24,stu
bl,female,26,star
# 显示第三列以2开头的 第1、3、4列
[hadoop1@hadoop1 test]$ awk -F, '$3~/^2/ {print $1,$3,$4}' s.txt
zzf 20 actor
zjm 22 actor
ycy 23 star
cxl 24 stu
bl 26 star
# 显示第4列以r结尾的 第1、3、4列
[hadoop1@hadoop1 test]$ awk -F, '$4~/r$/ {print $1,$3,$4}' s.txt
zzf 20 actor
zjm 22 actor
ycy 23 star
bl 26 star
# 显示第1列不包含c的第1、3列
[hadoop1@hadoop1 test]$ awk -F, '$1!~/c/ {print $1,$3}' s.txt
zzf 20
zjm 22
bl 26
# 对上面结果计数  wc -l
[hadoop1@hadoop1 test]$ awk -F, '$1!~/c/ {print $1,$3}' s.txt | wc -l
3

10.3.2、范围查询

  • /n/,/m/ 从n到m的行
  • NR=1,NR=5 从第1行到第5行
# 显示年龄从20到24的第一列姓名和第3列年龄
[hadoop1@hadoop1 test]$ awk -F, '/20/,/24/ {print $1,$3}' s.txt
zzf 20
zjm 22
ycy 23
cxl 24
# 显示 第1行到第3行 的 第1列和第3列
[hadoop1@hadoop1 test]$ awk -F, 'NR==1,NR==3 {print $1,$3}' s.txt
cxy 19
zzf 20
zjm 22

10.3.3、特殊条件 BEGIN() END()

模式解释应用场景
BEGIN()里面的内容会在awk读取文件之前执行1)简单统计,计算,不涉及读取文件
2)处理文件之前,添加表头
3)定义awk变量(很少用,因为有-v可以自定义变量)
END()⭐️里面的内容会在awk读取文件结束后执行1)awk统计,一般过程,先进行计算,最后END()输出结果
2)awk数组,用来输出数组结果
  • 统计方法
统计方法简写应用场景
i=i+1i++计数,统计次数
sum=sum+asum+=a求和,累加
# 对文件/etc/services的空行计数 
	# wc -l 计数
hadoop1@hadoop1 test]$ awk '/^$/' /etc/services | wc -l
17
	# 找出空行,有一空行就执行一次i++;最后END{}输出结果
[hadoop1@hadoop1 test]$ awk '/^$/{i++}END{print i}' /etc/services 
17
# 不加END 会输出17行17

# 计算1—100的和 seq 100 列出1—100
[hadoop1@hadoop1 test]$ seq 100 | awk '{sum+=$1}END{print sum}'
5050
# 显示计算过程 {sum+=$1;print sum}
[hadoop1@hadoop1 test]$ seq 10 | awk '{sum+=$1;print sum}END{print sum}'
1
3
6
10
15
21
28
36
45
55
55

10.4、awk数组

  • 之前对shell数组总结过,这里再与awk数组进行对比复习以下。
shell数组awk数组
赋值array[0]=1 array[1]=2array[0]=1 array[1]=2
取值echo ${array[0]}print array[0]
批量输出数组for i in ${array[@]} do echo $i donefor (i in array) print array[i]
数组统计array[$n]++ 对第n列分组统计
  • 例子:数组array有两个值1234和get 通过awk命令进行创建并读取。
    在进行创建数组赋值时,如果是字符型,必须用双引号将字符引起来,因为awk会将字符当作变量
# array[1]=get 会将get当作一个变量来看,而get没有创建并赋值,因此不输出array[1]
[hadoop1@hadoop1 ~]$ awk 'BEGIN{array[0]=1234;array[1]=get;print array[0],array[1]}'
1234 
# array[1]="get" 这里将get作为一个字符串赋值给数组array的第2个值即array[1]
[hadoop1@hadoop1 ~]$ awk 'BEGIN{array[0]=1234;array[1]="get";print array[0],array[1]}'
1234 get
# 遍历数组array :for (i in array) print i 这里的i是array的下标 而不是对应的值(在python中i就直接值得是相对应的值)
[hadoop1@hadoop1 test]$ awk 'BEGIN{array[0]=1234;array[1]="get";for (i in array) print i}'
0
1
# awk数组获取元素 array[i]
[hadoop1@hadoop1 test]$ awk 'BEGIN{array[0]=1234;array[1]="get";for (i in array) print array[i]}'
1234
get
  • 示例:处理以下文件,将网址前缀取出并计数排序处理
# 数据
[hadoop1@hadoop1 test]$ cat web.txt
http://www.etiantian.org/index.html
http://mp3.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/2.html
http://www.etiantian.org/index.html
http://mp3.etiantian.org/3.html
# 很明显 指定分隔符// / . ;对第2列www等进行分组统计(array[]++) 最后遍历输出结果  默认不排序
[hadoop1@hadoop1 test]$ awk -F"[/.]+" '{array[$2]++}END{for (i in array) print i,array[i]}'  web.txt
www 2
mp3 3
post 1
# 降序排列 sort -rnk2  (-k num 指定按照第num列排序; -r 降序排序,默认升序; -n 以数值型进行排序)
[hadoop1@hadoop1 test]$ awk -F"[/.]+" '{array[$2]++}END{for (i in array) print i,array[i]}'  web.txt |sort -rnk2
mp3 3
www 2
post 1

10.5、awk循环与判断

10.5.1、for循环

		shell编程C语言for循环
for ((i=1;i<10;i++));do
    echo $i
done;    


		awk for循环
for (i=1;i<10;i++)
	print i
  • 计算1—10的和 (为了更清晰 使用awk脚本)
## 下面这句awk文件必须要有。 指明这是个awk文件 需用awk命令读取
#!/bin/awk -f   
BEGIN{
# for 循环计算和
for (i=1;i<=10;i++)
	sum1+=i
print sum1

print "=============================="
# for循环 显示计算过程 for 循环里的程序需要用{}括起来 否则print只会在for循环结束后运行一次即效果和上面的一样 
for (i=1;i<=10;i++)
     {sum2+=i
	print sum2}
      }
# awk运行脚本文件 -f指明需要读取awk文件
[hadoop1@hadoop1 test]$ awk -f a.awk   
55
==============================
1
3
6
10
15
21
28
36
45
55

10.5.2、if判断

              shell 的if 语句
if [条件] ; then
	echo ''
elif [[条件1&&条件2]]; then
	echo ''
else 
	echo ''
fi			

               awk if 语句
if (条件)
	print ''
elif (条件)
	print ''
else
	print ''			
  • 判断当前磁盘使用情况
[hadoop1@hadoop1 test]$ df -h
文件系统        容量  已用  可用 已用% 挂载点
devtmpfs        975M     0  975M    0% /dev
tmpfs           991M     0  991M    0% /dev/shm
tmpfs           991M   11M  980M    2% /run
tmpfs           991M     0  991M    0% /sys/fs/cgroup
/dev/sda3        12G  5.1G  7.0G   42% /
/dev/sda1       976M  140M  770M   16% /boot
tmpfs           199M   36K  199M    1% /run/user/1000
/dev/sr0        4.4G  4.4G     0  100% /run/media/hadoop1/CentOS 7 x86_64
[hadoop1@hadoop1 test]$ df -h | awk -F"[ %]+" 'NR>1{if($5>40)print $1,$5,"磁盘不足"}'
/dev/sda3 42 磁盘不足
/dev/sr0 100 磁盘不足
  • 统计下面单词中字符数小于6的单词,显示出来
# 数据 a.txt
I am a student I like eating apple and playing basketball.
# 命令行筛选
[hadoop1@hadoop1 test]$ awk '{for(i=1;i<NF;i++)print$i}' a.txt
I
am
a
student
I
like
eating
apple
and
playing
# length awk内置函数 用来计算字符串长度
[hadoop1@hadoop1 test]$ awk '{for(i=1;i<NF;i++) if(length($i)<6) print$i}' a.txt
I
am
a
I
like
apple
and

##### 使用awk脚本筛选 a.awk
#!/bin/awk -f
{
for(i=1;i<=NF;i++)
    if(length($i)<6)
        print $i
}

[hadoop1@hadoop1 test]$ awk -f a.awk a.txt
I
am
a
I
like
apple
and
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值