shell脚本编程(5)——shell三剑客(grep、sed、awk)
这一章主要写的是linux系统三大文本处理工具grep、sed及awk的介绍以及各自优缺点,能够
快速掌握在文本中过滤,编辑,格式化的一些快捷功能(* ^ - ^ *)
目录
shell脚本编程(5)——shell三剑客(grep、sed、awk)
一、grep过滤工具
1、grep概述
-
grep全称是Global Regular Expression Print
-
grep命令是一款强大的文本搜索工具
-
他能使用用正则表达式搜素文本,并把匹配的行打印出来(使用正则表达式需要转义符号( 反斜杠\ ))
- 它的使用权限是所有用户。
- 格式: grep “ 查找条件” 文件名
2、egrep用法
-
使用正则表达式不需要用转义符号( 反斜杠\ )
-
egrep过滤工具 = grep -E
- 常用的命令选项
i :忽略字母大小写
v :条件取反
c :统计匹配的行数
q :静默、无任何输出,一般用于检测(用$?检测 )
n :显示出匹配结果所在的行号
--color :标红色显示匹配的字符串
- grep具体用法看上一篇文章
二、sed流式编辑器
1、sed概述
-
sed全称是:Stream Editor(流式编辑器)
-
逐行处理,并将结果输出到屏幕
-
可以非交互式实现增删改查,逐行处理
-
可实现对文本的输出、删除、替换、复制、剪切、导入、导出等各种操作
2、sed命令格式解析
- 主要用法:两种
格式1:前置命令 | sed [选项] ‘编辑指令’ #执行完上条命令后管道给sed命令处理
格式2:sed [选项] ‘编辑指令’ 文件… #直接编辑文件
- 常见命令选项
-n 屏蔽默认输出(全部文本)
-i 直接修改文本内容
-r 启用扩展正则表达式,若与其他选项一起用,应作为首个选项
- 常用的动作指令行
p 打印行
sed -n ‘1p’ a.txt //查看文本的第1行
sed -n ‘1,3p’ a.txt //查看文档第1到3行
sed -n ‘1,+3p’ a.txt //查看文档第1-4行
sed -n ‘1p,5p’ a.txt //查看第1和第5行
sed -n ‘1~2p’ a.txt //查看奇数行
sed -n ‘2~2p’ a.txt //查看偶数行
sed -n ‘=’ a.txt //查看行号
sed -n ‘$=’ a.txt //查看最后一行的行号
sed -n ‘$p’ a.txt //查看最后一行
使用正则表达式做定址符:
sed -n '/root/p' user //输出有root的行
sed -n '/^bin/p' user //输出以bin开头的行sed -n '/root/!p' user 输出没有root的行
d 删除行
sed ‘d’ a.txt //删除所有行
sed ‘1d’ a.txt //删除第一行
sed ‘1,3d’ a.txt //删除第1到第3行
sed ‘1,+3d’ a.txt //删除第1第4行
sed ‘1d,3d’ a.txt //删除第一和第三
sed '1~2d' a.txt //删除奇数行
sed '2~2d' a.txt //删除偶数行
sed '$d' a.txt //删除最后一行
使用正则表达式做定址符:
sed '/root/d' user //删除有root的行
sed '/root/!d' user // 删除没有root的行
s 字符串替换
(替换分隔符“/” “s/old/new/” “/g”代表所有替换)
(使用\1标签可调用本组表达式内的第一个用()保存的结果)
(使用#来分隔带/的目录名 ‘s#/bin/bash#/mnt/xixi#’ \为转义符号)
sed 's/2017/XXXX/' a.txt //替换所有行的第1个2017为XXXX
sed 's/2017/XXXX/2' a.xtx //替换所有行的第2个2017为XXXX
sed 's/2017/XXXX/g' a.xtx //替换所有行的所有2017为XXXX
sed '1s/2017/XXXX/' a.xtx //替换第1行的第1个2017
sed '1,2s/2017/XXXX/' a.xtx //替换第1~2行的第1个2017
sed '2,+1s/2017/XXXX/' a.xtx //替换第2行以及后面1行的第1个2017
sed '/2024/s/2017/XXXX/' a.xtx //替换有2024的行的第1个2017
sed '1s/2017/XXXX/;3s/2017/XXXX/' a.xtx //替换第1行和第3行的2017
- /bin/bash 替换成 /sbin/sh(\转义符号)
sed 's/\/bin\/bash/\/sbin\/sh/' user 方案一
sed 's#/bin/bash#/sbin/sh#' user 方案二
- 文本块处理动作符
i 在行的上面插入文本
sed '/root/i 666' user //有root的行上添加666
sed '2i 666' user //第2行上添加666
a 在行的下面插入文本
sed 'a 666' user //所有行下追加666
sed '1a 666' user //第1行下追加666
sed '/root/a 666' user //有root的行下追加666
c 替换整行
sed '3c 666' user //第3行替换为666
sed 'c 666' user //所有行替换为666
- 文件导入导出
r 读取文件 (结合-i选项才会存入,否则只输出)
sed ‘2r a.txt’ user //在第二行下插入a.txt文件
sed ‘/^abc/r a.txt’ user //在含abc开头的行下插入a.txt文件
w 保存到文件 (动作以覆盖的方式另存为新文件)
sed -n ‘1,2w a.txt’ user //将第一到第二行另存为a.txt文件
sed -n ‘/^XX/w a.txt ’ user
sed -n ‘/^XX/p’ user > a.txt //效果同上 ,将以XX开头的行另存为a.txt文件
- sed流控制
! 取反操作 (用途:根据地质条件取反)
sed -n ‘/bash$/!p’ /etc/passwd //列出不使用bash的用户账号记录
3、sed综合脚本应用
- 按照 "用户名 --> 密码" 的格式输出使用bash做解释器的用户信息
#!/bin/bash u=`sed -n '/bash$/s/:.*//p' /etc/passwd` //提取使用bash的用户名称 for i in $u //将使用bash的用户交给for循环 do p=`grep "$i" /etc/shadow` //找出shadow文件中对应的用户的行 p1=${p#*:} //将此行掐头 p2=${p1%%:*} //再去尾,得到密码信息 echo "$i --> $p2" //按需求输出 done
三、awk格式化工具
1、awk工具概述
- AWK是一个优良的文本处理工具、awk编程语言/数据处理引擎
- Linux及Unix环境中现有的功能最强大的数据处理引擎之一。
创造者:Aho、Weinberger、Kernighan (以三位创作者首字母命名)
基于模式匹配检查输入文本,逐行处理并输出
通常用在shell脚本红,获取指定的数据
单独使用时。可对文本数据做统计(不能修改文本的内容)
2、命令格式解析
- 主要用法(两种)
格式①:前置命令 | [选项] ‘[条件]{指令}’
格式②:awk [选项] ‘ [条件]{指令}’ 文件名…
{指令}:多条语句可以用分号分隔、print是最常用的指令
[选项]: -F :指定分隔符,默认可以省略(默认为空格或Tab位)
-
awk内置变量(有特殊含义,可以直接使用)
变量 | 用途 |
---|---|
FS | 保存活设置字段分隔符,例如FS=":" 与-F功能一样 |
$n | 指定分隔的第n哥字段,如字段$1、$3分别表示第1、第三列 |
$0 | 当前读入的整行文本内容 |
NF | 记录当前处理行的字段个数(列数) |
NR | 记录当前已读入行的数量(行数) |
awk '{print $1,$2,$3}' test //输出1~3列
awk '{print $3}' test //输出第3列
awk '{print $0}' test //输出文档原内容
awk '{print $1,$0}' test //输出第1列,再加文档原内容
awk '{print NR}' test //输出每行的行号
awk '{print NF}' test // 输出每行有多少列
awk '{print $NF}' test // 输出每行有最后一个字段
awk '{print "test"}' test //输出常量test
awk '{print "test"$1 }' test //常量+变量混合输出
awk '{print test }' test //不加双引号,识别为变量,未定义的变量内容为空
awk -F: '{print $1}' /etc/passwd //定义冒号为分隔符,输出第1列
awk -F: '{print $1"的解释器是"$7}' user //定义新分隔符后,输出常量+变量(常量加双引号)
- awk工作流程的控制
格式:awk [选项] ' BEGIN{指令} {指令} END{指令}' 文件
BEGIN{ } 行前处理,读取文件内容前执行,指令执行1次
{ } 逐行处理,读取文件过程中执行,指令执行n次
END{ } 行后处理,读取文件结束后执行,指令执行1次
- 案例1 :按格式输出文档内容
awk -F: 'BEGIN{print "User\tUID\tHome"}{print $1"\t"$3"\t"$6}END{print "总计"NR"行"}'/etc/passwd
a先输出首行为User UID Home(\t代表是自动空格对齐)
b再输出每行的第一第三第六列
c最后输出统计行数
- 案例2:统计系统中使用bash作为登录Shell的用户总个数
awk 'BEGIN{x=0}/bash$/{x++}END{print x}' /etc/passwd
a.预处理时赋值变量x=0
b.然后逐行读入/etc/passwd文件,如果发现登录Shell是/bin/bash则x加1
c.全部处理完毕后,输出x的值即可。
3、awk处理条件
- 正则表达式设置条件
格式:awk [选项] ‘/正则表达式/{指令}’ 文件名…
包含~ 不包含!~
awk -F: '/bash$/{print}' /etc/passwd //输出以bash结尾的行
awk -F: '/root/' /etc/passwd //执行一个条件{print}可以省略
awk -F: '$1~/root/' /etc/passwd //输出第1列包含root的行
awk '/^(127|192)/' /etc/hosts //输出以127或者192开头的行
awk -F: '$7!~/nologin$/{print $1,$7}' /etc/passwd //输出第7列不包含nologin的行的第1、第7列
- 数值/字符串比较设置条件
等于 == 不等于!=
大于 > 大于等于 >=
小于 > 小于等于 >=
awk 'NR==2{print}' reg.txt //输出第2行文本
awk '$2!="XX"{print}' reg.txt //输出第2列不是XX的行
awk 'NF>=2{print}' reg.txt //输出包含2个及以上字段的行
- 逻辑测试条件[q1]
&& 逻辑与:期望多个条件都成立(并且)
|| 逻辑或:只要有一个条件成立即满足要求(或者)
awk -F: '$3>1000&&$3<1005' /etc/passwd //找第3列是1001~1004的
awk -F: '$3>=1000&&$3<=1005' /etc/passwd // 找第3列是1000~1005的
awk 'NR>=2&&NR<=3' user //输出第2~3行
awk 'NR<=2&&NR==5' user //逻辑错误,无输出
awk 'NR<=2||NR==5' user // 输出1~2行与第5行
awk -F: '$3>10&&$3<20' /etc/passwd // 输出uid大于10小于20的
awk -F: '$3<10||$3>1000' /etc/passwd // 输出uid小于10或者大于1000的
awk -F: '$3<10&&$3>1000' /etc/passwd //无输出(没有小于10又大于1000的数
awk -F: '$3>10&&$3<1000' /etc/passwd //输出uid是11~999的
- 变量的运算
相当于一种运算工具
+ 、- 、* 、/ 、%
++ 、-- 、+= 、-= 、*= 、/=
awk 'BEGIN{x++;print x}' //输出1(x默认为0,x++为1)
awk 'BEGIN{print 2+3}' // 输出5,相当于计算2+3
seq 30 | awk '$1%3==0' //找出30以内3的倍数、seq 30 (按行列出显示1-30)
4、awk综合脚本应用
- 找到使用bash作登录Shell的本地用户、列出这些用户的shadow密码记录
- 编写脚本的任务要求如下:
分析出使用bash作登录Shell的本地用户
列出这些用户的shadow密码记录
按每行“用户名 -- 密码记录”保存结果
- 思路:
提取符合条件的账号记录 awk -F: '/bash$/{print $1}' /etc/passwd
显示用户配置文件第一、第二列 grep "$i:" /etc/shadow |awk -F: '{print $1" --> "$2}'
- 具体脚本:
#!/bin/bash
u=`awk -F: ‘/bash${print $1}’ /etc/passwd`
for i in $u
do
grep “$i:” /etc/shadow | awk -F: ‘{print $1”-->”$2}’ //“$i:”加冒号是为了屏蔽再次显示所有
done
4、awk流程控制
- awk数组 (,可以存储多个值的特殊变量)
定义数组 格式:数组名[下标] =元素值 a[1]=10
调用数组 格式:数组名[下标] a[1]
遍历数组 用法:for(变量 in 数组名){print 数组名[变量]}
用数组做运算:a[1]=11;a[1]++
awk 'BEGIN{a[1]=11;a[2]=22;print a[1]}' //定义数组名为a,下标是1,值是11,
awk 'BEGIN{a[1]=11;a[2]=22;print a[2]}' //再定义新下标2,值是22,然后输出下标是1的值
awk 'BEGIN{a0++;print a0}' //下标值不定义默认为0
awk 'BEGIN{a[0]++;print a[0]}' //定义下标和值时可以不使用数字
- for语句
格式:for(变量 in 数组名){print 数组名[变量]}
awk '{ip[$1]++}END{for(i in ip){print ip[i],i}}' /var/log/httpd/access_log |sort -nr //统计网站访问量,并按照降序排列
- if语句
单分支: if(条件){编辑指令}
双分支: if(条件){编辑指令}else{编辑指令2}
多分支: if(条件){编辑指令}else if{编辑指令2}else if{编辑指令3}…else{编辑指令N}
awk -F: ‘{if($3<=1000){i++}}END{print i}}’ /etc/passwd //统计/etc/passwd文件中UID小于或等于1000的用户个数
awk -F: '{if($3<=1000){i++}else{j++}}END{print i,j}' /etc/passwd //分别统计/etc/passwd文件中UID小于或等于1000、UID大于1000的用户个数
awk -F: '{if($7~/bash/){x++}else if($7~/nologin/){y++}else{z++}}END{print x,y,z}' /etc/passwd //分别统计/etc/passwd文件中登录Shell是“/bin/bash”、 登录Shell是“/bin/nologin”、登录Shell不是“/bin/bash” 也不是“/bin/nologin”的用户个数
- 扩展:sort 命令
支持常用的排序功能
默认情况下,sort命令,以字母序进行文本排序,再到数字
格式:sort [ 选项 ] 文件名
-n 按字符串数值升序排序
-r 降序排序,默认为升序
-u 去除重复的行
-o 将输出写入文件
-k 指定按哪一列排序
5、awk综合案例
- 案例1:编写监控脚本
CPU负载
网卡流量
内存剩余容量
磁盘剩余容量
计算机账户数量
当前登录账户数量
计算机当前开启的进程数量
本机已安装的软件包数量
[root@svr5 ~]# vim test.sh
#!/bin/bash
ip=`ifconfig eth0 | awk '/inet /{print $2}'`
echo "本地IP地址是:"$ip
cpu=`uptime | awk '{print $NF}'` #awk中NF为当前行的列数,$NF是最后一列
echo "本机CPU最近15分钟的负载是:"$cpu
net_in=`ifconfig eth0 | awk '/RX p/{print $5}'`
echo "入站网卡流量为:"$net_in
net_out=`ifconfig eth0 | awk '/TX p/{print $5}'`
echo "出站网卡流量为:"$net_out
mem=`free | awk '/Mem/{print $4}'`
echo "内存剩余容量为:"$mem
disk=`df | awk '/\/$/{print $4}'`
echo "根分区剩余容量为:"$disk
user=`cat /etc/passwd |wc -l`
echo "本地账户数量为:"$user
login=`who | wc -l`
echo "当前登陆计算机的账户数量为:"$login
process=`ps aux | wc -l`
echo "当前计算机启动的进程数量为:"$process
soft=`rpm -qa | wc -l`
echo "当前计算机已安装的软件数量为:"$soft
- 案例2:编写安全检测脚本
发现登录服务器输入密码错误超过3次时,将信息发邮件给管理员
#!/bin/bash
x=`awk '$0!~/invalid/&&/Failed/{ip[$11]++}END{for(i in ip){print ip[i],i}}' /var/log/secure |awk '{if($1>3){print "目前有主机"$2"尝试登陆服务器,尝试次数为"$1"次"}}'`
[ -z $x ] || echo "$x" |mail -s test root
结束啦
这篇的基本介绍就先写到这里,shell脚本的一些基本知识总结到这,后面会继续更新shell脚本的一些常用的用法以及企业中一些实用的shell脚本的运用,感谢你们的浏览,也希望对你们有所帮助,你的点赞是我努力的动力,谢谢你们!