第五章、三剑客
正则表达式
前言
名词解释:正则表达式(regular expression,RE)是一种字符模式,用于在查找过程中匹配指定的字符。在大多数程序里,正则表达式都被置于两个正斜杠之间;例如/l[oO]ve/就是由正斜杠界定的正则表达式,它将匹配被查找的行中任何位置出现的相同模 式。在正则表达式中,元字符是最重要的概念。
工具:被vim、sed、awk、grep调用
场景:mysql、oracle、php、python,Apache,Nginx...需要正则
回顾:
需求:匹配数字的脚本:用户输入创建账号的数量
语法:[[ ^[0-9]+$ ]]
示范:
read -p "输入数字才退出:" num
while :
do
if [[ ! $num =~ ^[0-9]+$ ]];then
echo "error enter!"
read -p "输入数字才退出:" num
else
echo "thank you"
exit 1
fi
done
元字符
定义:元字符是这样一类字符,它们表达的是不同于字面本身的含义
分类
基本正则表达式元字符
^:行首定位符
[root@localhost ~]# grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]#grep "^root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
$:行尾定位符
love$
.:匹配任意单个字符
[root@localhost ~]# grep abc 1.txt
abc
[root@localhost ~]# grep adc 1.txt
adc
[root@localhost ~]# grep a.c 1.txt
abc
adc
*:匹配前导符(字符、子表达式或字符类)0次到多次出现
[root@localhost ~]# cat 1.txt
a
ab
abc
abcd
abcde
abcdef
ggg
hhh
[root@localhost ~]# grep "abc*" 1.txt
ab
abc
abcd
abcde
abcdef
[root@localhost~]# grep "abcd*" 1.txt
abc
abcd
abcde
abcdef
.*:匹配任意多个字符
[root@localhost ~]# grep ".*" 1.txt
a
ab
abc
abcd
abcde
abcdef
ggg
hhh
iii
[ ]:匹配指定范围内的一个字符 [IL]ove
[root@localhost ~]# cat 1.txt
love
Love
1ove
iove
[root@localhost ~]#grep [IL]ove 1.txt
love
Love
[-]:匹配指定范围内的一个字符,连续的范围
[A]:匹配不在指定组内的字符
\:用来转义元字符(' ' " " \),脱意符
\<:词首定位符
[root@localhost ~]# grep "love" 1.txt
love
iloveyou
[root@localhost ~]# grep "\love" 1.txt
love
\>:词尾定位符 love\>
():\(..\) 匹配稍后使用的字符的标签
:3,9 s/\(.*\)/#\1 /加注释
x\{m\}: 字符x重复出现m次
[root@localhost ~]# grep o 1.txt
love
loove
looove
[root@localhost ~]# grep "o\(3\)" 1.txt
looove
x\{m,\}:字符x重复出现m次以上 o\{5,\}
x\m,n\}:字符x重复出现m到n次 o\{5,10\}
扩展正则表达式元字符
+:匹配1~n个前导字符
[root@localhost ~]# cat 1.txt
Ive
love
loove
[root@localhost ~]#egrep lo+ve 1.txt
love
loove
?:匹配0~1个前导字符 lo?ve:?前面的无论是否有o都可以
[root@localhost ~]# egrep lo?ve tom.sh
love
Ive
a|b:匹配a或b
[root@localhost ~]# egrep "o|v" 1.txt
lve
love
loove
looove
():组字符
[root@localhost ~]# egrep "loveable | rs"1.txt
rs
loveable
lovers
[root@localhost~]# egrep "love(able|rs)" 1.txt
loveable
lovers
示例
grep love 1.txt
/^love/:匹配以"love"开头的字段。
/love$/:匹配以"love"结尾的字段。
/l.ve/:匹配包含"l"、任意字符、"ve"的字段。
/lo*ve/:匹配包含"l"、零个或多个"o"、"ve"的字段。
/[Ll]ove/:匹配"Love"或"love"。
/love[a-z]/:匹配"love"后面跟着任意一个小写字母的字段。
/love[^a-zA-Z0-9]/:匹配"love"后面跟着任意一个非字母和非数字字符的字段。
/.*/:匹配任意字符。
/^$/:匹配空字段。
/^[A-Z]..$/:匹配以大写字母开头,后面跟着任意两个字符的字段。
/^[A-Z][a-z ]*3[0-5]/:匹配以大写字母开头,后面跟着零个或多个小写字母或空格,以及以"3"后面跟着0到5之间的数字结尾的字段。
/[a-z]*\./:匹配零个或多个小写字母后面跟着一个句点的字段。
/^ *[A-Z][a-z][a-z]$/:匹配以零个或多个空格开头,后面跟着一个大写字母,最后是两个小写字母的字段。
/^[A-Za-z]*[^,][A-Za-z]*$/:匹配以零个或多个字母开头,后面跟着一个非逗号字符,最后是零个或多个字母的字段。
/\<fourth\>/:匹配单词"fourth"。
/\<f.*th>/:匹配以"f"开头,后面跟着任意个字符,最后是"th"的字段。
/5{2}2{3}\./:匹配"55222"后面跟着一个句点的字段。
/^[ \t]*$/:匹配以零个或多个空格或制表符开头并且没有其他字符的字段。
/^#/:匹配以"#"开头的字段。
/^[ \t]*#/:匹配以零个或多个空格或制表符开头,后面跟着一个"#"的字段。
:1,$ s/\([Oo]ccur\)ence/\1rence/:将"Occurence"或"occurence"替换为"Occurrence"或"occurrence"。
:1,$ s/\(square\) and \(fair\)/\2 and \1/:将"square and fair"替换为"fair and square"。
grep
目的:过滤,查找文档中的内容
分类:
grep
egrep 扩展支持正则
\w 所有字母与数字,称为字符 [a-zA-Z0-9] 'l[a-zA-Z0-9]*ve' === '|\w*ve'
\W 所有字母与数字之外的字符,称为非字符 'love[^a-zA-Z0-9]+' === 'love\W+'
\b 词边界 '\' === '\blove\b'
fgrep 不支持正则
[root@localhost ~]# fgrep.1.txt
I.ve
返回值
- 0是找到了 表示成功;
- 1是没有找到
- 2是找到地方不对
示范:
## grep 'root' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
## echo $?
0
## grep 'root1' /etc/passwd #用户root1并不存在
## echo $?
1
## grep 'root' /etc/passwd1 #这里的/etc/passwd1文件并不存在
grep:/etc/passwd1: No such file ordirectory
## echo $?
2
参数
grep -q:静默模式,用于在命令行中查找匹配的文本,但不显示匹配结果。它通常用于脚本中,只关心匹配与否,而不需要显示具体匹配内容。
grep -v:反向匹配模式,用于在命令行中查找不匹配的文本。它会显示不包含指定模式的行。
grep -R:递归搜索模式,用于在指定目录及其子目录下搜索匹配的文本。它会搜索目录中的所有文件,并显示包含匹配模式的行。
grep -o:只显示匹配的部分,而不显示整行。它会提取出匹配模式的部分,并将其显示出来。
grep -B2:显示匹配行及其前两行。它会显示包含匹配模式的行,并显示前两行作为上下文。
grep -A2:显示匹配行及其后两行。它会显示包含匹配模式的行,并显示后两行作为上下文。
grep -C2:显示匹配行及其前后两行。它会显示包含匹配模式的行,并显示前后两行作为上下文。
egrep -l:只显示匹配模式的文件名,而不显示具体匹配内容。它用于在多个文件中查找匹配模式,并只显示包含匹配模式的文件名。
egrep -n:显示匹配行及其行号。它会显示包含匹配模式的行,并在每行前面显示行号。
示例
grep -E或egrep 进行使用
# egrep 'NW' datafile.txt:在"datafile.txt"中查找包含"NW"的行。
# egrep 'NW' d*.txt:在以"d"开头的txt文件中查找包含"NW"的行。
# egrep '^n' datafile.txt:在"datafile.txt"中查找以"n"开头的行。
# egrep '4$' datafile.txt:在"datafile.txt"中查找以"4"结尾的行。
# egrep TB Savage datafile.txt:在"datafile.txt与Savage"中查找包含"TB "的行。
# egrep 'TB Savage' datafile.txt:在"datafile.txt"中查找包含"TB Savage"的行。
# egrep '5\..' datafile.txt:在"datafile.txt"中查找以"5"开头,后跟一个点和任意字符的行。
# egrep \.5' datafile.txt:在"datafile.txt"中查找包含".5"的行。
# egrep '^[we]' datafile.txt:在"datafile.txt"中查找以"we"开头的行。
# egrep '[^0-9]' datafile:在"datafile.txt"中查找不包含数字的字符。
# egrep '[A-Z][A-Z] [A-Z]' datafile:在"datafile.txt"中查找包含三个大写字母的行。
# egrep 'ss* ' datafile:在"datafile.txt"中查找包含"s"后跟零个或多个s的行。
# egrep '[a-z]{9}' datafile: 在"datafile.txt"中查找出现了九次小写字母的行。
# egrep "^north" 在"datafile.txt"中查找以"north"开头的行。
# egrep '\<north>' datafile:在"datafile.txt"中查找单词"north"。
# egrep '\<[a-r].*n\>' datafile:在"datafile.txt"中查找以字母"a"到"r"开头,后跟零个或多个字符,最后以"n"结尾的单词。
# egrep '^n\w*\W' datafile:在 "datafile" 文件中查找以字母 "n" 开头,后跟零个或多个字母、数字或下划线字符,最后以一个非字母、数字或下划线字符结尾的单词
# egrep '\bnorth\b' datafile:在"datafile.txt"中查找单词"north"。
# egrep 'NW | EA' datafile:在"datafile.txt"中查找包含"NW"或"EA"的行。
# egrep '3+' datafile:在"datafile.txt"中查找包含一个或多个"3"的行。
# egrep '2\.?[0-9]' datafile:在"datafile.txt"中查找以"2"开头,后跟零个或一个点,再后跟一个数字的行。
# egrep '(no)+' datafile:在"datafile.txt"中查找包含一个或多个"no"的行。
# egrep 'S(h|u)' datafile:在"datafile.txt"中查找包含"Sh"或"Su"的行。
# egrep 'Sh|u' datafile\:在"datafile.txt"中查找包含"Sh"或"u"的行。
sed
前言
Stream EDitor:流编辑
sed是一种在线的、非交互式的编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”( patternspace),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。
接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。Sed主要用来自动编辑 个或多个文件;简化对文件的反复操作;
格式
1 sed 选项 命令 文件
sed [options] 'command' file(s)
2 sed 选项 -f 脚本 文件
sed [options] -f scriptfile file(s)
返回值
都是0,对错不管。
只有当命令存在语法错误时,sed的退出状态才是非0
sed和正则表达式
与grep一样,sed在文件中查找模式时也可以使用正则表达式(RE)和各种元字符。
正则表达式是括在斜杠间的模式,用于查找和替换,以下是sed支持的元字符。
使用基本元字符集 ^,$,.,*,[],[^], \,\(\),\{\}
使用扩展元字符集 ?,+,|,()
使用扩展元字符的方式:
\+ 转义
sed -r 加-r用于启用扩展正则表达式语法
汇总示例
删除命令: d
# sed -r '/root/d' passwd
在名为 passwd 的文件中删除包含关键字 "root" 的行。
# sed -r '3d' passwd
在名为 passwd 的文件中删除第三行。
# sed -r '3{d}' passwd
在名为 passwd 的文件中删除第三行。这里使用了花括号 {} 来指定要执行的命令,即删除行。
# sed -r '3{d;}' passwd
在名为 passwd 的文件中删除第三行。与上一个命令相比,这里使用了分号 ; 来分隔多个命令。d 表示删除行。
# sed -r '3,$d' passwd
在名为 passwd 的文件中删除从第三行到最后一行的内容。3,$ 表示从第三行到最后一行的范围。
# sed -r '$d' passwd
在名为 passwd 的文件中删除最后一行。
替换命令:s
# sed -r 's/root/aofa/' passwd
在名为 passwd 的文件中将第一个匹配到的 "root" 替换为 "aofa"。
# sed -r 's/^root/aofa/' passwd
在名为 passwd 的文件中将以 "root" 开头的行替换为以 "aofa" 开头的行。
# sed -r 's/root/aofa/g' passwd
在名为 passwd 的文件中将所有匹配到的 "root" 替换为 "aofa"。g 表示全局替换,即替换所有匹配项。
# sed -r 's/[0-9][0-9]$/&.5/' passwd
在名为 passwd 的文件中将以两个数字结尾的行,在行尾添加 ".5"。[0-9][0-9]$ 表示匹配以两个数字结尾的模式,& 表示匹配到的内容本身。
# sed -r 's/(mail)/E\1/g' passwd
在名为 passwd 的文件中将所有匹配到的 "mail" 替换为 "Email"。(mail) 使用括号捕获 "mail",\1 表示捕获组的引用。
# sed -r 's#(mail)#E\1#g' passwd
在名为 passwd 的文件中将所有匹配到的 "mail" 替换为 "Email"。(mail) 使用括号捕获 "mail",\1 表示捕获组的引用。这里使用 # 作为替换命令的分隔符,以避免与斜杠冲突。
读文件命令:r
# sed -r '$r 1.txt' passwd
在名为 passwd 的文件的末尾追加来自 1.txt 文件的内容。$ 表示最后一行,r 表示读取文件并将其内容追加到当前行之后。
# sed -r '/root/r 1.txt' passwd
在名为 passwd 的文件中,对于包含关键字 "root" 的行,在该行之后追加来自 1.txt 文件的内容。/root/ 是一个模式,r 表示读取文件并将其内容追加到匹配行之后。
VI中也有类似命令
(#vim 1.txt
111111111
2222222
3333333333
aaaaaa
bbbbbb
CCCCCC
:$ r a.txt)
在当前文件中,读取其他文件“部分”内容。
写文件命令:W(另存为)
# sed -r 'w 111.txt' 1.txt
将名为 1.txt 的文件的内容写入到名为 111.txt 的文件中。w 表示写入操作。
# sed -r '/root/w 123.txt' passwd
将名为 passwd 的文件中包含关键字 "root" 的行写入到名为 123.txt 的文件中。/root/ 是一个模式,w 表示写入操作。
# sed -r '1,5w 123.txt' passwd
将名为 passwd 的文件的第1行到第5行的内容写入到名为 123.txt 的文件中。1,5 表示行的范围,w 表示写入操作。
追加命令:a(之后)
# sed -r 'a123' passwd
在名为 passwd 的文件中的每一行后面添加字符串 "123"。a 表示追加操作。
# sed -r '2a123' passwd
在名为 passwd 的文件的第二行后面添加字符串 "123"。2 表示第二行,a 表示追加操作。
# sed -r '2a 1111\
> 3333333\
> 444444' passwd
在名为 passwd 的文件的第二行后面添加多行文本。\用于换行,a 表示追加操作。
插入命令:i(之前)
# sed -r '2iaaaaaaaa' passwd
在名为 passwd 的文件的第二行之前插入字符串 "aaaaaaaa"。2 表示第二行,i 表示插入操作。
# sed -r '2i 123\
>456\
> 789' passwd
在名为 passwd 的文件的第二行之前插入多行文本。\用于换行,i 表示插入操作。
替换整行命令:c
# sed -r '2caaaaaaaa' passwd
将名为 passwd 的文件的第二行替换为字符串 "aaaaaaaa"。
获取下一行命令:n
# sed -r '/root/{n;d}' passwd
在名为 passwd 的文件中,对于包含关键字 "root" 的行,删除包含关键字 "root" 的行的下一行。
# sed -r /root/{n;s/bin/ding/g}' passwd
在名为 passwd 的文件中,对于包含关键字 "root" 的行,将其下一行中的 "bin" 替换为 "ding"
反向选择:!
# sed -r '2,$d' passwd
删除名为 passwd 的文件中从第二行到最后一行的内容。
# sed -r '2,$!d' passwd
删除名为 passwd 的文件中除了第二行到最后一行之外的所有行。
多重编辑:e
# sed -r -e '1,3d' -e '4s/adm/admin/g' passwd
它使用了两个 -e 选项来指定多个表达式。第一个表达式 1,3d 表示删除名为 passwd 的文件中的第一行到第三行。第二个表达式 4s/adm/admin/g 表示在第四行中将所有的 "adm" 替换为 "admin"。
# sed -r '1,3d;4s/adm/admin/g' passwd
它使用了分号 ; 来分隔多个表达式。第一个表达式 1,3d 表示删除名为 passwd 的文件中的第一行到第三行。第二个表达式 4s/adm/admin/g 表示在第四行中将所有的 "adm" 替换为 "admin"。
# sed -r '2s/bin/ding/g;2s/nologin/bash/" passwd
使用了分号 ; 来分隔多个表达式。第一个表达式 2s/bin/ding/g 表示在第二行中将所有的 "bin" 替换为 "ding"。第二个表达式 2s/nologin/bash/ 表示在第二行中将 "nologin" 替换为 "bash"。
# sed -r '2{s/bin/ding/g;s/nologin/bash/}' passwd
它使用了花括号 {} 来指定要在第二行上执行的多个表达式。第一个表式 s/bin/ding/g 表示在第二行中将所有的 "bin" 替换为 "ding"。第二个表达式 s/nologin/bash/ 表示在第行中将 "nologin" 替换为 "bash"。
实战案例
删除配置文件中#号注释行
# sed -r /^#/d' /etc/vsftpd/vsftpd.conf
修改文件:
# sed -ri '$a\chroot_local_user=YES' /etc/vsftpd/vsftpd.conf
在/etc/vsftpd/vsftpd.conf文件的末尾添加一行内容chroot_local_user=YES。-i选项用于直接修改原始文件。
# sed -ri '/SELINUX=/cSELINUX=disabled' /etc/selinux/config
将/etc/selinux/config文件中包含SELINUX=的行替换为SELINUX=disabled。/c命令用于替换匹配的行。
给文件行添加注释:
# sed -r '2,6s/^/#/' a.txt
# sed -r '2,6s/(.*)/#\1/'a.txt
((.*):这是一个捕获组,用括号()括起来。它表示匹配任意数量的任意字符,并将其捕获到该组中。捕获组允许我们在替换中引用这个匹配的内容。/#\1/:这是替换字符串,其中/#表示要添加到替换结果中的#字符,而\1表示对第一个捕获组的引用。
当使用s/.../.../替换命令时,\1用于引用第一个捕获组的内容。在这种情况下,/#\1/表示将#字符添加到第一个捕获组的内容之前。)
# sed -r '2,6s/.*/#&/' a.txt
(当使用s/.../.../替换命令时,&用于引用与模式匹配的内容。在这种情况下,#&表示将
#字符添加到模式匹配的整个字符串之前。)
sed中使用外部变量
准备工作:# var1=11111
追加变量:# sed -r "1a$var1" /etc/hosts
注意调用变量时,使用单引号是错误的
巧合:
# sed -r "$a$var1" /etc/hosts
报错了,$a最后一行追加被误认为变量了。
# sed -r "\$a$var1"/etc/hosts
(\$a:这是一个sed命令,用于在文件的最后一行追加内容。在这里,\$表示匹配行尾,a表示追加操作。
$var1:这是一个变量,它的值将被追加到文件的最后一行。)
awk
一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。
基本用法
awk [选项参数] '/patternl/{action1} /pattern2/{action2}...' filename
pattern:表示awk在数据中查找的内容,就是匹配模式
action:在找到匹配内容时所执行的一系列命令
选项参数说明
选项参数 功能
-F 指定输入文件分隔符
-v 赋值一个用户定义变量
案例实操
(1)数据准备
[atguigu@hadoop101 shells]$ sudo cp /etc/pasawd ./ (将/etc/pasawd文件复制到当前目录下。)
passwd数据的含义:
用户名:密码(加密过后的):用户id:组id:注释:用户家目录:shell解析器
(2)搜索passwd文件以root关键字开头的所有行,并输出该行的第7列。
[atguigu@hadoop101 shells]$ awk -F :'/^root/{print $7}' pasawd
/bin/bash
(3)搜索passwd文件以root关键字开头的所有行,并输出该行的第1列和第7列,中间以“,”号分割。
[atguigu@hadoop101 shells]$ awk -F : '/^root/{print $1","$7}' passwd
root,/bin/bash
注意:只有匹配了pattem的行才会执行 action。
(4)只显示/etc/passwd的第一列和第七列,以逗号分割,且在所有行前面添加列名user,shell在最后一行添加"dahaige,/bin/zuishuai"。
[atguigu@hadoop101shells]$ awk -F : 'BEGIN{print "user,shell"} {print $1","$7} END{print "dahaige,/bin/zuishuai"} passwd
user,shelle
root,/bin/bashd
bin,/sbin/nologind
。。。
atguigu,/bin/bashd
dahaige,/bin/zuishuai
注意:BEGIN在所以数据读取行之前执行;END在所以数据执行之后执行。
(5)将passwd文件中的用户id增加数值1并输出
[atguigu@hadoop101shells]$ awk-v i=1 -F :{print $3+i}' passwd
1
2
3
4
awk的内置变量
变量 说明
FILENAME 文件名
NR 已读的记录数(行号)
NFI 浏览记录的域的个数(切割后,列的个数)
案例实操
(1)统计passwd文件名,每行的行号,每行的列数
[atguigu@hadoop101 shells]$ awk -F : '{print "filename:" FILENAME ",linenum:" NR ",col:" NF}' passwd
filename:passwd,linenum:1,col:7
filename:passwd,linenum:2,col:7
filename:passwd,linenum:3,col:7
...
(2)查询ifconfig命令输出结果中的空行所在的行号
[atguigu@hadoop101 shells]$ ifconfig | awk '/^$/{print NR}'
9
18
26
(3)切割IP
[atguigu@hadoop101 shells]$ ifconfig ens33 | awk '/netmask/ {print $2}'
192.168.6.101
cut
cut 的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。cut命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段输出。
基本用法
cut [选项参数] filename
说明:默认分隔符是制表符
选项参数说明
选项参数 功能
-f 列号,提取第几列
-d 分隔符,按照指定分隔符分割列,默认是制表符“\t”
-c 按字符进行切割 后面加n 表示取第几列 比如 -c 1
案例实操
数据准备
[atguigu@hadoop101 shells]$ touch cut.txte
[atquiqu@hadoop101 shells]$ vim cut.txt
dong shen
guan zhen
wo wo
lai lai
le le
切割cut.txt第一列
[atguigu@hadoop101 shells]$ cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le
切割cut.txt第二、三列
[atguigu@hadoop101 shells]$ cut -d " " -f 2,3 cut.txt
shen
wo
zhen
lai
le
在cut.txt文件中切割出 guan
[atguigu@hadoop101 shells]$ cat cut.txt | grep guan cut -d " " -f 1
guan
选取系统PATH变量值,第2个冒号开始后的所有路径:
[atguigu@hadoop101 shells]$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/atguigu/.local/bin:/ home/atguiqu/bin
[atguigu@hadoop101 shells]$ echo $PATH cut -d ":"-f 3-
/usr/local/sbin:/usr/sbin:/home/atguigu/.local/bin:/home/atguigu/bin
切割ifconfig 后打印的IP地址
[atguigu@hadoop101 shells]$ ifconfig ens33 | grep netmask cut -d " " -f 10
192.168.111.101