shell脚本——awk详细介绍(包含应用案例)
Posted 0611#
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell脚本——awk详细介绍(包含应用案例)相关的知识,希望对你有一定的参考价值。
三剑客awk详解
awk概述
- awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。
- 数据可以来自标准输入、一个或多个文件,或其他命令的输出。
- 它支持用户自定义函数和动态正则表达式等先进功能。
awk处理文本方式
- awk的处理文本和数据的方式是这样的,
- 它逐行扫描文件,从第一行到最后一行,
- 寻找匹配的特定模式的行,并在这些行上进行你想要的操作。
- 如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕)。
- awk分别代表其作者姓氏的第一个字母,因为他的作者是三个人,分别是Alfred Aho、Peter Weinberger、Kernighan。
awk工作原理
awk -F:'{print $1,$3}' /etc/passwd
- awk使用一行作为输入,并在这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束
- 然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始 最多达100个字段
- awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理,该过程将持续到所有行处理完毕
- 一行被称为记录,一个词称为字段
awk语法
awk [选项] '命令' 文件名 (推荐)
- 选项:例如 -F 定义输入字段分隔符,默认的分隔符是空格或制表符(tab)
- 命令(时空):过去 现在 将来
- BEGIN{}:begin发生在行处理前(注意大写)
- { } :行处理时,读一次执行一次
- END{}:=行处理之后
汇总示例
示例文件准备:为了使操作结果看起来简单易懂在每一行最后添加了数字
[root@pakho ~]# head /etc/passwd >passwd
[root@pakho ~]# cat passwd
root:x:0:0:root:/root:/bin/bash1
bin:x:1:1:bin:/bin:/sbin/nologin2
daemon:x:2:2:daemon:/sbin:/sbin/nologin3
adm:x:3:4:adm:/var/adm:/sbin/nologin4
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin5
sync:x:5:0:sync:/sbin:/bin/sync6
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
halt:x:7:0:halt:/sbin:/sbin/halt8
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin9
operator:x:11:0:operator:/root:/sbin/nologin10
内部变量
一、FS
<:输入字段分隔符(默认空格)
[root@pakho ~]# awk 'BEGIN{FS=":"}{print $1}' passwd #等同于-F:
- 效果展示
二、OFS
:输出字段分隔符
[root@pakho ~]# awk 'BEGIN{FS=":";OFS="++--++"}{print $1,$2,$3}' passwd
OFS定义输出的字符想怎么写就怎么写
- 效果展示
三、 RS
输入记录(行)分隔符,默认换行符
[root@pakho ~]# awk 'BEGIN{RS=":"}{print $0}' passwd #会把:当做一条记录
四、ORS
输出记录(行)分隔符,默认换行符
[root@pakho ~]# awk 'BEGIN{ORS="+++"}{print $0}' passwd
- 效果展示
五、FNR
多文件独立编号
准备了两个文件
[root@pakho ~]# awk '{print FNR,$0}' 1.txt passwd #查看了两个文件 但都会显示自己文件的独立编号
- 效果展示
六、NR
多文件汇总编号
[root@pakho ~]# awk '{print NR,$0}' 1.txt passwd #汇总行号
- 效果展示
七、★NF字段总数
[root@pakho ~]# awk '{print NF,$0}' 1.txt
- 效果展示
[root@pakho ~]# awk '{print $NF}' 1.txt #NF是6 那么$NF就是$6
格式化输出
print参数
[root@pakho ~]# awk -F: '{print "账号名:" $1}' passwd | head -1
账号名:root
[root@pakho ~]# awk -F: '{print "账号名:"$1" \\t用户的ID是:"$3}' passwd | head -2
账号名:root 用户的ID是:0
账号名:bin 用户的ID是:1 #-t是回车的意思
模式(正则表达)和动作
概念
- 任何awk语句都由模式和动作组成,模式部分决定动作语句何时触发及触发事件,
- 如果省略模式部分,动作将时刻保持执行状态,每一行都会有动作。
- 模式可以是任何条件语句或复合语句或正则表达式,有模式的话,就是对模式对应的行进行动作。
字符串比较
[root@pakho ~]# awk -F: '/^root/' passwd
[root@pakho ~]# awk -F: '$0 ~ /^root/' passwd #这一行记录好像是root开头的 $0表示记录 ~表示好像
root:x:0:0:root:/root:/bin/bash1
[root@pakho ~]# awk -F: '$0 !~ /^root/' passwd #这一行记录不像是root开头的 !取反
bin:x:1:1:bin:/bin:/sbin/nologin2
daemon:x:2:2:daemon:/sbin:/sbin/nologin3
adm:x:3:4:adm:/var/adm:/sbin/nologin4
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin5
sync:x:5:0:sync:/sbin:/bin/sync6
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
halt:x:7:0:halt:/sbin:/sbin/halt8
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin9
operator:x:11:0:operator:/root:/sbin/nologin10
数值比较
目的
- 比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作,比较表达式使用关系运算符,
- 用于比较数字与字符串
关系运算符
语法:
<
小于<=
小于或等于==
等于!=
不等于>=
大于等于>
大于
[root@pakho ~]# awk -F: '$3 > 10' passwd #查找id号大于10的账号
operator:x:11:0:operator:/root:/sbin/nologin10
[root@pakho ~]# awk -F: '$3 == 0' passwd #查找id号等于0的账号
root:x:0:0:root:/root:/bin/bash1
算术运算
语法:+ - * / %(模) ^(幂2 ^ 3 )
#示例
[root@pakho ~]# awk -F: '$3 * 5 > 50' passwd #文件中只有operator $3 * 5 大于50
operator:x:11:0:operator:/root:/sbin/nologin10
多条件运算
- 逻辑操作符和复合模式
语法
- &&逻辑与a&&b
- | | 逻辑与a | | b
- !逻辑非!a
#示例
[root@pakho ~]# awk -F: '$1 ~ /ro/&& $3 == 0' passwd #$1好像是ro 并且$3=0
root:x:0:0:root:/root:/bin/bash1
[root@pakho ~]# awk -F: '$1 ~ /r/&& $3 <= 10' passwd #拿出10的参数条件与之对比
root:x:0:0:root:/root:/bin/bash1
[root@pakho ~]# awk -F: '/adm/,/shutdown/' passwd #查询adm到shutdown的内容
adm:x:3:4:adm:/var/adm:/sbin/nologin4
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin5
sync:x:5:0:sync:/sbin:/bin/sync6
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
awk脚本编程
变量
awk调用变量
- 自定义内部变量 -v 参数
-v
:定义变量
[root@pakho ~]# awk -F: -v bianliang=shutdown '$1 == bianliang' passwd #定义变量bianliang 调用变量biangliang 查询shutdown
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
- 外部变量
" ' "
注意:awk使用外部变量时,外部使用双引号,内部也使用双引号,但需要转义内部的双引号
[root@pakho ~]# heihei=shutdown #首先定义外部变量
[root@pakho ~]# awk -F: '$1 ~ "'"$heihei"'"' passwd #调用变量
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
双重否定等于肯定所以使用三重否定需要加引号二次转义
条件判断
一、单分支 if语句
- 格式: if语句 格式{if(表达式{语句;语句;…})} if(条件测试){执行语句}
#需求:如果$3是0,就说他是管理员
[root@pakho ~]# awk -F: '{if($3==0){print $1 "是管理员"}}' passwd
root是管理员
二、双分支 if…else语句
- 格式:{if(表达式){语句;语句;…} else{语句;语句;…}} if(条件测试){条件成立执行语句}eles{条件不成立执行语句}
#需求:uid是0就说他是管理员否则就说他是普通用户
[root@pakho ~]# awk -F: '{if($3==0){print $1 "是管理员"} else {print $1 "是普通用户"}}' passwd
root是管理员
bin是普通用户
daemon是普通用户
adm是普通用户
lp是普通用户
sync是普通用户
shutdown是普通用户
halt是普通用户
mail是普通用户
operator是普通用户
#需求:统计管理员和系统用户数量
[root@pakho ~]# awk -F: '{if($3==0){i++}else{u++}}END{print i;print u}' passwd
1
9
三、 多分支 if…else if…else语句
- 格式:{if(表达式1){语句;语句;…}else if(表达式2){语句;语句;…}else if(表达式3){语句;语句…}}
#需求:统计出三种用户的信息,管理员ID为0 内置用户ID<1000 普通用户ID>999
[root@pakho ~]# awk -F: '{ if($3==0){a++} else if ($3>999){b++} else {c++} }END{print a;print b;print c}' /etc/passwd
1
2
24
[root@pakho ~]# awk -F: '{ if($3==0){a++} else if ($3>999){b++} else {c++} }END{print a "是超管";print b"是普通用户";print c"是内置用户"}' /etc/passwd
[root@pakho ~]# awk -F: '{if($3==0){print $1,"是超管"}else if($3>999){print $1,"是普通用户"}else{print $1,"是程序用户"}}' /etc/passwd
循环
一、while循环
#循环打印10个数字
[root@pakho ~]# awk 'BEGIN{while(i<=10){print i;i++}}' passwd
#每一行打印10次
[root@pakho ~]# awk -F: '{while(i<=9){print $0;i++}}' passwd
二、for循环
#循环打印5个数字
[root@pakho ~]# awk -F: 'BEGIN{for(i=1;i<=5;i++){print i}}'
#每行打印10次
[root@pakho ~]# awk -F: '{for(i=1;i<=10;i++){print $0}}' passwd
#打印每一行的每一列
[root@pakho ~]# awk -F: '{for(i=1;i<=10;i++){print $0}}' passwd
数组
一、定义数组
#需求:将用户名定义为数组的值,打印第一个值
[root@pakho ~]# awk -F: '{username[++i]=$1}END{print username[1]}' passwd
root
二、数组遍历
#按索引遍历
[root@pakho ~]# awk -F: '{username[++i]=$1}END{for(i in username){print username[i]}}' passwd
adm
lp
sync
shutdown
halt
mail
operator
root
bin
daemon
awk编程案例
#需求:统计/etc/passwd 中各种类型shell的数量
[root@pakho ~]# awk -F: '{shells[$NF]++}END{for(i in shells){print i,shells[i]}}' /etc/passwd
/bin/sync 1
/bin/bash 2
/sbin/nologin 22
/sbin/halt 1
/sbin/shutdown 1
#awk '/west/' datafile #找到west的行
#awk '/^north/'datafile #找north开头的行
#awk '$3 ~ /^north/' datafile #第三列是好像是以north开头
#awk '/^(no|so)/' datafile #找no开头或者so开头的
#awk '{print $3,$2}' datafile #打印第三列和第二列 ,是输出分隔符 默认输入空格
#awk '{print $3 $2}' datafile #打印第三列和第二列 但没有空格
#awk '{print $0}' datafile #打印一行 每一行都打印出来
#awk 'END{print "总列数是:"NF}' datafile #行处理之后打印行号
#awk '/northeast/{print $3,$2}' datafile #打印出含有northeast的第三列和第二列
#awk '/E/' datafile #打印出含有E的行
#awk '$5 ~ /\\.[7-9]+/' datafile #匹配第5列好像是以.7 .8 .9的 匹配多个
#awk '$2!~/E/{print $1,$2}' datafile #匹配不是以E开头的行 打印第1列和第2列
以上是关于shell脚本——awk详细介绍(包含应用案例)的主要内容,如果未能解决你的问题,请参考以下文章
自动化运维必须要学的Shell文本处理三剑客之——awk用法(超多案例详细介绍)