前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >文本处理三剑客之—awk

文本处理三剑客之—awk

作者头像
用户4877748
发布2020-07-22 10:18:42
1.1K0
发布2020-07-22 10:18:42
举报
文章被收录于专栏:LVMLVM

AWK is what?

    AWK是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

AWK基本用法?

代码语言:javascript
复制
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{ action;… }' file 

awk 程序通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块,共3部分组成

分割符、域和记录 awk执行时,由分隔符分隔的字段(域)标记1,2..n称为域标识,0为所有域,注意:和shell中变量符含义不同,文件的每一行称为记录,省略action,则默认执行 print 0 的操作。

AWK工作原理?

第一步:执行BEGIN{action;… }语句块中的语句 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。 第三步:当读至输入流末尾时,执行END{action;…}语句块BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中 END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块,pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

通俗理解:awk工作流程是这样的:先执行BEGIN,然后读取文件,读入有/n换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,0则表示所有域,1表示第一个域,

1:AWK常用变量

FS:输入字段分隔符,默认为空白字符

代码语言:javascript
复制
awk -v FS=':' '{print $1,FS,$3}' /etc/passwd
awk –F: '{print $1,$3,$7}' /etc/passwd

OFS:输出字段分隔符,默认为空白字符

代码语言:javascript
复制
[root@localhost ~]# awk -F:  '{print $1,$3,$7}' /etc/passwd 
root 0 /bin/bash
bin 1 /sbin/nologin
daemon 2 /sbin/nologin
adm 3 /sbin/nologin
lp 4 /sbin/nologin


[root@localhost ~]# awk -F: -v OFS=':' '{print $1,$3,$7}' /etc/passwd 
pulse:497:/sbin/nologin
sshd:74:/sbin/nologin
tcpdump:72:/sbin/nologin
junchao:500:/bin/bash
qijunchao:501:/bin/bash

NF:字段数量

代码语言:javascript
复制
awk -F: ‘{print NF}’ /etc/fstab,引用内置变量不用$   #输出/etc/fstab下每一行域的个数
                                                                            
awk -F: '{print $(NF-1)}' /etc/passwd  #表示输出倒数第二域的内容

NR:行号

代码语言:javascript
复制
[root@localhost ~]# awk '{print NR}' /etc/fstab 
1
2
3
4
[root@localhost ~]# awk END'{print NR}' /etc/fstab 
4
[root@localhost ~]# 

printf格式化输出

代码语言:javascript
复制
[root@localhost ~]# awk -F: '{printf "Username:%s UID:%s\n",$1,$3}' /etc/passwd
Username:root UID:0
Username:bin UID:1
#左对齐
[root@localhost ~]# awk -F: '{printf "Username:%-15s UID:%s\n",$1,$3}' /etc/passwd
Username:root            UID:0
Username:bin             UID:1

三目表达式  selector?if-true-expression:if-false-expression

代码语言:javascript
复制
[root@localhost ~]# awk -F: '{$3>=500?usertype="Common User":usertype="Sys User";printf "UserName:%-15s Type:%s\n",$1,usertype}' /etc/passwd
UserName:root            Type:Sys User
UserName:bin             Type:Sys User
UserName:junchao         Type:Common User
UserName:qijunchao       Type:Common User

模式匹配符:~:左边是否和右边匹配包含!~:是否不匹配

代码语言:javascript
复制
[root@localhost ~]# awk '$0 ~ "^root" {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# awk -v FS=: '$3 == 0 {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# 

lag'}' 结果为abcd awk '{print "

2:AWK控制语句

条件语句:

if... else if...else

代码语言:javascript
复制
[root@localhost ~]# awk -v FS=: '{if($3>=1000){usertype="Common User"}else if($3==0)
{usertype="SuperUser"}else{usertype="SysUser"}printf"UserName:%-15sType:%s\n",$1,usertype}' /etc/passwd
UserName:root            Type:Super User
UserName:bin             Type:Sys User

循环语句:

while

代码语言:javascript
复制
[root@localhost ~]# cat /boot/grub/grub.conf  |awk '/^[[:space:]]*kernel/{i=1;while(i<=NF){print $i,length($i);i++}}'
kernel 6
/vmlinuz-2.6.32-696.el6.x86_64 30
ro 2
root=UUID=d98fccb0-b74e-4de3-9953-27b74542267a 46
rd_NO_LUKS 10
rd_NO_LVM 9
LANG=en_US.UTF-8 16

do...while

代码语言:javascript
复制
[root@localhost ~]# awk 'BEGIN{ total=0;i=0;do{ total+=i;i++;}while(i<=100);print total}'
5050

for循环

代码语言:javascript
复制
[root@localhost certs]# awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {print $i,length($i)}}' /etc/grub2.cfg
linux16 7
/vmlinuz-3.10.0-862.el7.x86_64 30
root=UUID=fbbc6de7-b727-41f8-b18b-90e56dc412b3 46
ro 2
crashkernel=auto 16
rhgb 4
quiet 5

break和continue

代码语言:javascript
复制
[root@localhost certs]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==10)break;sum+=i}print sum}'
45
[root@localhost certs]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){if(i==10)continue;sum+=i}print sum}'
5040
[root@localhost certs]# 

next: 提前结束对本行处理而直接进入下一行处理(awk自身循环)

代码语言:javascript
复制
[root@localhost certs]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd
root 0
daemon 2
lp 4
shutdown 6
mail 8
games 12

3:数组

awk中的数组的下标可以是数字和字母,称为关联数组。

用变量作为数组下标。如:

代码语言:javascript
复制
$ awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}' test

数组name中的下标是一个自定义变量x,awk初始化x的值为0,在每次使用后增加1。第二个域的值被赋给name数组的各个元素。在END模块中,for循环被用于循环整个数组,从下标为0的元素开始,打印那些存储在数组中的值。因为下标是关健字,所以它不一定从0开始,可以从任何值开始。

用域值作为数组的下标。for (index_value in array) statement。

例:统计/etc/passwd下bash类型以及个数

代码语言:javascript
复制
[root@localhost ~]# awk -F: '{line[$7]++}END{for(i in line){print i,line[i]}}' /etc/passwd
/sbin/shutdown 1
/bin/bash 3
/sbin/nologin 26
/sbin/halt 1
/bin/sync 1

4:awk的内建函数

字符串函数

sub      sub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容,并将第一个匹配的内容替换为s

代码语言:javascript
复制
[root@localhost ~]# echo "2018:08:29 10:08:30" |awk 'sub(/:/,"-",$1)'
2018-08:29 10:08:30

gsub     gsub(r,s,[t]):对t字符串进行搜索r表示的模式匹配的内容

代码语言:javascript
复制
[root@localhost ~]# echo "2018:08:29 10:08:30" |awk 'gsub(/:/,"-",$1)'
2018-08-29 10:08:30

   对t字符串进行搜索r表示的模式匹配的内容,并全部替换为s所表示的内容

代码语言:javascript
复制
[root@localhost ~]# echo "2018:08:29 10:08:30" |awk 'gsub(/:/,"-",$0)'
2018-08-29 10-08-30

查找字符串(index使用)

代码语言:javascript
复制
[root@localhost ~]# awk 'BEGIN{info="this is a test2018test!";print index(info,"test")?"ok":"no found";}'    
ok
[root@localhost ~]# awk 'BEGIN{info="this is a test2018test!";print index(info,"kobe")?"ok":"no found";}'    
no found

正则表达式匹配查找(match使用)

代码语言:javascript
复制
[root@localhost ~]# awk 'BEGIN{info="this is a test2018test!";print match(info,/[0-9]+/)?"ok":"no found";}'           
ok
[root@localhost ~]# awk 'BEGIN{info="this is a testhellotest!";print match(info,/[0-9]+/)?"ok":"no found";}'           
no found

截取字符串(substr使用)

代码语言:javascript
复制
[root@localhost ~]# awk 'BEGIN{info="this is a test2018test!";print substr(info,4,10);}'                         
s is a tes

字符串分割(split使用)

代码语言:javascript
复制
[root@localhost ~]# awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'
4
4 test
1 this
2 is
3 a

分割info,动态创建数组tA,这里比较有意思,awk for …in 循环,是一个无序的循环。 并不是从数组下标1…n ,因此使用时候需要注意。

如何把一行竖排的数据转换成横排?

代码语言:javascript
复制
[root@localhost ~]# awk '{printf("%s,",$1)}' testfile 
hello,nihai,haizi,yuanren,daren,test,file,kobe,manba,
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-09-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

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