正则表达式概述
概述
使用“一串符号”来描述有共同属性的数据
基本正则列表
扩展正则列表
准备素材
[root@localhost ~]# head -5 /etc/passwd > user
[root@localhost ~]# cat user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
测试 ^ $
[root@localhost ~]# grep root user
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# grep ^root user
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# grep root$ user
[root@localhost ~]# grep bash$ user
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# vim user
[root@localhost ~]# grep ^$ user #^$代表空行
[root@localhost ~]# cat user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
5
[root@localhost ~]# grep -v ^$ user # -v 取反的意思,查询除空行之外的,空格这些也代表字符
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
5
[ ] 集合
匹配集合内任意一个字符,至少有一个就匹配成功
[^ ] 对集合取反
grep "[root]" user #找r、o、t任意一个字符
grep "[rot]" user #效果同上
grep "[^rot]" user #显示r或o或t以外的内容
grep "[0123456789]" user #找所有数字
grep "[0-9]" user #效果同上
grep "[^0-9]" user #显示数字以外内容
grep "[a-z]" user #找所有小写字母
grep "[A-Z]" user #找所有大写字母
grep "[a-Z]" user #找所有字母
grep "[^0-9a-Z]" user #找所有符号
练习:编写脚本,问用户要整数数字,如果用户没有按要求则给出提示
#!/bin/bash
read -p "请输入一个整数数字: " n
echo $n | grep "[^0-9]"
[$? -ne 0 ] && echo ok || echo "必须输入数字
. 匹配单个字符
* 匹配前一个字符任意次数,不可以单独使用
.* 连接起来代表通配符
[root@localhost ~]# grep "*" user
[root@localhost ~]# grep "ro*t" user
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# grep ".*" user
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
5
测试 \{n\} \{n,\} \{n,m\} \(\)
grep "ro\{1,2\}t" user #找rt,中间的o可以有1~2个
grep "ro\{2,6\}t" user #找rt,中间的o可以有2~6个
grep "ro\{1,\}t" user #找rt,中间的o可以有1个以及1个以上
grep "ro\{3\}t" user #找rt,中间的o必须只有有3个
grep "\(0:\)\{2\}" user #找连续的2个0: 小括号的作用是将字符组合为一个整体
扩展正则
grep "ro\{1,\}t" user #使用基本正则找o出现1次以及1次以上
egrep "ro{1,}t" user #使用扩展正则,效果同上,比较精简
egrep "ro+t" user #使用扩展正则,效果同上,最精简
grep "roo\{0,1\}t" user #使用基本正则找第二个o出现0~1次
egrep "roo{0,1}t" user #使用扩展正则,效果同上,比较精简
egrep "roo?t" user #使用扩展正则,效果同上,最精简
egrep "(0:){2}" user #找连续的2个0: 小括号的作用是将字符组合为一个整体
egrep "root|bin" user #找有root或者bin的行
egrep "the\b" abc.txt #找单词the,右边不允许出现数字、字母、下划线
egrep "\bthe\b" abc.txt #the两边都不允许出现数字、字母、下划线
egrep "\<the\>" abc.txt #效果同上
思考:如何匹配大范围的数字?比如250-255
方法一:
[root@localhost ~]# grep "25[0-5]" shuzi.txt
253 456 234 34 254
方法二:
[root@localhost ~]# egrep "250|251|252|253|254|255" shuzi.txt
253 456 234 34 254
sed基本用法 (sed流式编辑器,逐行处理)
概述
可以对文档进行非交互式增删改查
格式
前置指令 | sed 选项 条件 指令
sed 选项 条件 指令 文档
选项、指令、条件
选项 -n 屏蔽默认输出
选项 -r 支持扩展正则
选项 -i 修改源文件
指令 p 输出 d 删除 s 替换
条件 行号 正则表达式
行号案例
head -5 /etc/passwd > user #准备素材
sed -n 'p' user #输出所有行
sed -n '1p' user #输出第1行
sed -n '2p' user #输出第2行
sed -n '3p' user #输出第3行
sed -n '2,4p' user #输出2~4行
sed -n '2p;4p' user #输出第2行与第4行
sed -n '3,+1p' user #输出第3行以及后面1行
sed -n '1~2p' /etc/passwd #输出奇数行
sed -n '2~2p' /etc/passwd #输出偶数行
使用正则为条件
使用正则当条件
sed -n '/^root/p' user #输出以root开头的行
sed -n '/root/p' user #输出包含root的行
sed -nr '/^root|^bin/p' user #输出以root开头的行或bin开头的行,|是扩展正则,需要r选项
特殊用法
sed -n '1!p' user #输出除了第1行的内容,!是取反
sed -n '$p' user #输出最后一行
sed -n '=' user #输出行号,如果是$=就是最后一行的行号
sed命令的s替换基本功能(s/旧内容/新内容/选项)
[root@svr5 ~]# vim shu.txt #新建素材
2017 2011 2018
2017 2017 2024
2017 2017 2017
sed 's/2017/6666/' shu.txt #把所有行的第1个2017替换成6666
sed 's/2017/6666/2' shu.txt #把所有行的第2个2017替换成6666
sed '1s/2017/6666/' shu.txt #把第1行的第1个2017替换成6666
sed '3s/2017/6666/3' shu.txt #把第3行的第3个2017替换成6666
sed 's/2017/6666/g' shu.txt #所有行的所有个2017都替换
sed '/2024/s/2017/6666/g' shu.txt #找含有2024的行,将里面的所有2017替换成6666
思考:如果想把 /bin/bash 替换成 /sbin/sh 怎么操作?
sed综合脚本应用
实现以下需求:
- 找到使用bash作登录Shell的本地账户名
- 列出这些账户的shadow密码记录
- 按每行“账户名 --> 密码记录”保存到文件中
#!/bin/bash
u=$(sed -n '/bash$/s/:.*//p' /etc/passwd) #找到passwd文档中以bash结尾的行,然后将行中冒号以及冒号后面内容都删除,此处的p代表仅仅显示s替换成功的行,最后赋值给u
for i in $u #将那些用bash的账户名交给for循环
do
pass=$(grep $i /etc/shadow) #用每个账户名去shadow中找对应信息
pass=${pass#*:} #掐头,从左往右删除到第1个冒号
pass=${pass%%:*} #去尾,从右往左删除到最后一个冒号,经过上述步骤,pass就是最终要的密码了
echo "$i --> $pass" #按格式喊出,如果要存到文件中就用追加重定向
done
正则表达式补充
\w 匹配数字、字母、下划线
egrep "roo\w" user #找roo后面必须是数字或字母或下划线的字符串
\s 匹配空格、tab键
egrep "roo\s" user #找roo后面是1个空格或者tab键打出来的空格的字符串,如果没有
就不输出
\d 匹配数字,和[0-9]等效
egrep "(25[0-5]\.|2[0-4][0-9]\.|1?[0-9]?[0-9]\.){3}(25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])" #匹配ip地址
grep -P "(25[0-5]\.|2[0-4]\d\.|1?\d?\d\.){3}(25[0-5]|2[0-4]\d|1?\d?\d)" #匹配ip地址
练习
匹配IP地址
sed补充
a行下追加 i行上添加 c替换整行
sed 'a 666' user #所有行的下面追加666
sed '1a 666' user #第1行的下面追加666
sed '/^bin/a 666' user #在以bin开头的行的下面追加666
sed 'i 666' user #所有行的上面添加666
sed '5i 666' user #第5行的上面添加666
sed '$i 666' user #最后1行的上面添加666
sed 'c 666' user #所有行都替换成666
sed '1c 666' user #替换第1行为666
( )保留功能测试,保留就是复制的意思
cat abc.txt #先准备素材
100 laowang
98 gangge
59 laoniu
sed -r 's/([0-9]+)(\s+)([a-z]+)/\3\2\1/' abc.txt #使用替换功能更改文本列,此处小括号相当于保留(复制),\1相当于粘贴之前第1个小括号里的内容