欢迎大家来到IT世界,在知识的湖畔探索吧!
关键词:Linux,Shell,awk
内容摘要
- awk简介
- awk语法快速开始
- awk命令参数设置
- awk设置变量
- 正则匹配过滤pattern,match
- 条件判断过滤,类比SQL
- action操作语法,类比SQL
- awk任务实战
awk简介
awk是一个强大的文本分析工具,尤其是对linux中的结构化二维表数据可以实现类似SQL的检索,统计,替换功能。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理,是一种能够完成文本遍历,正则匹配,逻辑判断,结果操作的shell代码集合,使得开发者能够更方便地在linux上进行文件操作
- 功能支持:文本匹配,文本转化,文本统计分析
- 操作对象:文件或者标准输入
- 工作方式:逐行扫描`文件,从第一行到最后一行,执行匹配和操作逻辑
awk语法快速开始
awk基本语法如下
- awk ‘pattern’ filename
- awk ‘{action}’ filename
- awk ‘pattern {action}’ filename
其中pattern代表匹配条件,action代表对目标内容进行的操作,filename代表文件,其中filename(或者标准输入输出)必不可少,pattern和action二者必须有其中一个,否则无法运行。一共支持三种方式,表明awk支持仅文件内容匹配,仅文件内容操作和先匹配指定文件内容再做操作三种模式,下面对这三种模式进行快速上手
1.仅文件内容匹配
若awk没有设置action操作,则action默认是print,即将匹配到的内容进行打印输出。比如使用正则匹配出/etc/group文件中存在docker字符的整行,匹配某个完整字符的pattern语法是/pattern/
awk '/docker/' /etc/group docker:x:999:
欢迎大家来到IT世界,在知识的湖畔探索吧!
另一种是条件过滤匹配,例如精确匹配第一个元素为docker的行,精确匹配需要对匹配内容加双引号,用双等于==进行判断
欢迎大家来到IT世界,在知识的湖畔探索吧!awk 'BEGIN{FS=":"}$1=="docker"' /etc/group docker:x:999,test
其中BEGIN{}代表该句awk的处理前逻辑,在该例的作用是设置全局变量FS分隔符为冒号,$1是被分割后每行的第一个元素,索引从1开始,$0代表整行
2.仅文件内容操作
若awk没有设置匹配条件则不做任何筛选拿到全部内容,此时操作是针对全部内容比如一个文件的所有行,默认操作是打印匹配到的内容,也可以自定义操作,比如打印分隔后的第一个元素而不是整行
awk 'BEGIN{FS=":"}{print $1}' /etc/group sambashare mysql docker
3.先匹配指定文件内容再做操作
pattern和action结合先筛选出符合的行再做统一操作,例如筛选包含docker的行输出第一个元素
欢迎大家来到IT世界,在知识的湖畔探索吧!awk 'BEGIN{FS=":"}/docker/{print $1}' /etc/group docker
4.对标准输出进行操作
可以对标准输出做awk操作,产生标准输出的方式有cat,echo等,以及可以在控制台输出的工具,例如使用cat的输出
cat /etc/group |awk 'BEGIN{FS=":"}{print $1}' root daemon bin sys adm
使用echo的输出取出空格分隔后的第二个元素
echo "1 2 3 4" |awk '{print $2}' 2
使用其他命令到控制台的输出,比如docker images命令的输出筛选镜像
docker images | awk '/mysql/' mysql 5.7 09361feeb475 5 months ago 447MB mysql latest 5c62e459e087 5 months ago 556MB
awk命令参数设置
在上一节中已经介绍了awk的简单用法和作用,本节详细看下awk可以设置的参数,常用参数如下
命令选项 |
描述 |
-F |
指定文本分隔符,默认是Tab或者空格 |
-v |
在复杂逻辑中设置变量 |
‘ ‘ |
引用代码块 |
-f |
-f或者-file,从脚本文件中读取awk命令 |
BEGIN |
初始化代码块,在每一行处理之前运行,设置处理逻辑的全全局变量 |
END |
结尾代码块,在每一行处理完之后再执行,输出最终的计算结果 |
{} |
代码块,编写处理逻辑,BEGIN和END后面也需要{} |
对其中几个进行测试,-F文本问个符号
echo "1,2,3,4" |awk -F "," '{print $2}' 2
BEGIN用于在awk匹配逻辑之前设置全局变量,必须大写例如设置内置分隔符为冒号
awk 'BEGIN{FS=":"}{print $1}' /etc/group
也可以设置自定义变量,变量的命名由用户自定义,如果有多个变量中间用分号;隔开,在引用的时候action中直接引用变量名(不加$)
awk 'BEGIN{FS=":";v1="用户组是"}{print v1$1}' /etc/group 用户组是mysql 用户组是docker
该例设置了自定义变量v1,赋值为字符串“用户组是”,在action中引用进行格式化打印
-v设置awk全局变量,可以在action中引用设置的变量,效果和在BEGIN中设置一样
awk -v v1="用户组是:" -v v2=" gid是" 'BEGIN{FS=":"}{print v1$1v2$2}' /etc/group 用户组是:mysql gid是xxx 用户组是:docker gid是xxx
END用于在遍历完每一行后进行一个计算操作,最终得出全部计算结果,例如统计总共遍历了多少行
awk 'BEGIN{FS=":";cnt=0}{cnt+=1}END{print cnt}' /etc/group 71
该例中先自定义了一个变量cnt=0,action操作每遍历一行cnt+=1,这个和cat /etc/group |wc -l结果一致
awk设置变量
对于awk来说变量又分为内置变量和自定义变量,awk中包含很多内置变量,比如说-F命令默认的分隔符是Tab或者空格,实际上就是awk的内部变量FS来控制的,内置变量的目的是在awk代码中进行修改和引用,常用的内置变量如下
变量名 |
描述 |
$0 |
当前记录,整个一行记录 |
$1~$n |
当前记录被分隔符分割之后的元素,根据索引位置排 |
FS |
字段分隔符 默认是空格 |
NF |
字段个数,就是有多少列 |
NR |
行号,从1开始 |
RS |
记录之间的分隔符,默认是换行符 |
FILENAME |
当前输入文件的名字 |
IGNORECASE |
如果为真,则进行忽略大小写的匹配 |
NF输出分隔后字段个数
echo '1 2 3 4' |awk '{print NF}' 4
NR显示行号,比如选取70行以上的
awk 'BEGIN{FS=":"}NR>70{print $0}' /etc/group test:x:1001:
复杂一点取偶数行,直接拿到NR计算即可
awk 'BEGIN{FS=":"}NR%2==0{print $0}' /etc/group
IGNORECASE忽略大小写,比如用在精确匹配中大写匹配规则可以匹配小写内容
awk 'BEGIN{FS=":";IGNORECASE=1}$1=="Docker"{print $0}' /etc/group docker:x:999:test
具体是将IGNORECASE加入BEGIN中,1是开启,0是关闭,默认关闭
正则匹配过滤pattern,match
pattern部分支持正则表达式的语法,比如以下案例加入了正则表达式的元素
^符号匹配行首,比如查看ls的是文件夹的,以d开头
ll |awk /^d/ drwxr-xr-x 5 root root 4096 12月 9 17:25 ./ drwxr-xr-x 62 root root 4096 12月 13 14:36 ../ drwxr-xr-x 4 root root 4096 7月 29 18:48 bisai/ drwxrwxr-x 2 root root 4096 2月 20 2019 docker/
$匹配结尾,匹配以f结尾的行
echo -e "dsd\nsdslhf\nssdf\n" |awk '/f$/' sdslhf ssdf
[ ]匹配字符集,可以完成多个字符集中任何一个字符的匹配,比如匹配以d或者s开头的并且第二个字符是s的结果
echo -e "dsd\nkdslhf\nssdf\n" |awk '/^[ds]s/' dsd ssdf
[^ ]排他设置,和字符集匹配相反,只要不在指定的字符集内其他的都算匹配到,比如匹配首字母不是k和s的所有行
echo -e "dsd\nkdslhf\nssdf\n" |awk '/^[^ks]/' dsd
match函数:macth可以返回指定要匹配内容,类似通用的正则表达式,格式如下
match($0,/pattern/,a);action
在match函数中$0代表对整行进行匹配,对ip地址进行匹配,匹配结果赋值到变量a,在action阶段拿到a匹配到的指定内容
ifconfig wlp2s0|grep netmask |awk '{match($0,/([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/,a); print a[1]}' 192.168.43.59
条件判断过滤
条件过滤部分可以实现单分之和多分支逻辑,类似于SQL的Where语句,语法如下
awk 'BEGIN{}条件{action}END{}'
例如统计每行第三个字段姓名是小王的行数,相当于SQL的select count… where…
awk '$3=="小王"{i++}END{print i}' info.txt 21
其中$3==”小王“是条件放在最前面,{i++}是action初始的变量i为0,最后调用print打印出统计值,在这个基础上再增加一个条件,第四列学历是小学的,相当于select count… where…and…
awk '$3=="工商"&&$4=="小学"{i++}END{print i}' info.txt 6
使用&&完成条件的交集,同理并集使用||,代表或的逻辑。也可以完成检索展示的工作,例如检索A列姓名等于某值时B列分数的值
awk '$3=="小王"{print $2}' info.txt 33 22 12
action操作语法
action对每一行过滤后的结构进行操作,除了打印,还可以在这一步完成统计分析的逻辑编写,比如实现select sum的功能,对一列累加求和
awk -F "," '{sum+=$2}END{print sum}' score.txt 1315
使用action可以实现类似SQL group by的功能,分组统计个数,类似于select count(1) group by,比如
awk '{x[$3]+=1}END{for(i in x){print i,x[i]}}' score.txt 语文 5 数学 1 英语 21
实现的方式是在action中定义一个关联数组x,然后往里面添加key和+1,在END中再遍历一次即可,如果不使用awk而是写shell定义数组和遍历需要很长一段,如下
#/bin/bash unset x declare -A x while read line do key=`echo $line |awk -F ' ' '{print $3}'` x[$key]=$[${x[$key]}+1] done<score.txt for i in ${!x[@]} do echo $i,${x[$i]} done
在action里面可以加入条件筛选,相当于action也可以包含pattern的功能,比如统计出每行第三个字段是语文的行数,相当于SQL的select count …where…
awk '{if($3=="语文")i++}END{print i}' score.txt 10
再加一个分之判断,统计一下语文和数学,多个判断条件之间要用;分号隔开,如果不用分号需要将条件判断后面的代码加{}代码段
awk '{if($3=="语文") i++; else if($3=="数学") j++;}END{print i,j}' score.txt 21 10
同样还可以完成SQL的判断输出任务,相当于case when
awk '{if($3=="语文")print "数据源是语文"; else if($3=="数学")print "数据源是数学"; else print "数据源是其他"}' score.txt 数据源是其他 数据源是语文 数据源是数学 数据源是其他
实际上action可以一步到位,将条件和操作全部写在action里面,多条件分之注意在else,else if之前增加分号
awk任务实战
一个常用的任务是从配置文件中获取某个key的value,传入Shell脚本中进行处理,例如有这样一个yml文件
cat config.yml mysql_host: 172.17.0.1 mysql_port: 3306 mysql_user: aaa mysql_password:
现要从中获取其中的mysql_host
awk -F ':' '$1=="mysql_host"{gsub(" ","",$0);print $2}' config.yml 172.17.0.1
其中gsub用来替换空格,顺序为先调用gsub去除空格,在使用-F进行分割,再判断$1==”mysql_host。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/81410.html