文章目录
引言
在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
一、正则表达式
1.正则表达式概述
正则表达式通常用于判断语句中,用来检查某一字符串是否满足某一格式。
正则表达式是由普通字符与元字符组成。普通字符包括小写字母、数字、标点符号及一些其他符号。元字符是指在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。
2.正则表达式的分类
正则表达式根据从POSIX BRE或者POSIX ERE标准可以分为基本正则表达式和扩展正则表达式。
基本正则表达式
支持的工具:grep
、egrep
、sed
、 awk
,注意grep
要配合-E
或者-P
使用。
元字符 | 含义及用法 |
---|---|
\ | 转义字符,用于取消特殊符号的含义,例: \! 、 \n 、 \$ 等 |
^ | 匹配字符串开始的位置,例:^a 、^the 、^# 、^[a-z] |
$ | 匹配字符串结束的位置,例: word$ 、^$ 匹配空行 |
. | 匹配除\n 之外的任意的一个字符,例: go.d 、g..d 。如果想要匹配包含\n字符可以使用 [.\n] |
* | 匹配前面子表达式0次或者多次,例: goo*d 、 go.*d |
[list] | 匹配list列表中的一个字符,例: go[ola]d ,[abc] 、[a-z] 、[a-z0-9] 、[0-9] 匹配任意一位数字 |
[^list] | 匹配任意非list列表中的一个字符,例:[^0-9] 、[^A-Z0-9] 、[^a-z] 匹配任意一位非小写字母 |
\{n\} | 匹配前面的子表达式n次,例: go\{2\}d 、 [0-9]\{2\} 匹配两位数字 |
\{n,\} | 匹配前面的子表达式不少于n次,例: gol{2,l}d 、[0-9]\{2,\} 匹配两位及两位以上数字 |
\{n,m\} | 匹配前面的子表达式n到m次,例 : go\{2,3\}d 、[0-9]\{2,3\} 匹配两位到三位数字注: egrep 、 awk 使用{n} 、{n,} 、{n,m} 匹配时 {} 前不用加 \ |
\w \W | 匹配包括下划线的任何单词字符。 匹配任何非单词字符。等价于 [^A-Za-z0-9_] 。 |
\d \D | 匹配一个数字字符。 匹配一个非数字字符。等价于 [^0-9] 。 |
\s \S | 空白符。 非空白符。 |
扩展正则表达式
支持的工具:egrep
、awk
,注意:使用grep
要配合-E
或者-P
使用,sed
要配合-r
使用。
元字符 | 含义及用法 |
---|---|
+ | 匹配前面子表达式1次以上,例: go+d ,将匹配至少一个o ,如god 、good 、goood 等 |
? | 匹配前面子表达式0次或者1次,例: go?d ,将匹配gd 或god |
() | 将括号中的字符串作为一个整体,例1: g(oo)+d ,将匹配oo 整体1次以上,如good 、gooood 等 |
| | 以或的方式匹配字符串,例:g(oo|la)d ,将匹配good 或者 glad |
3.正则表达式的使用
* ^ $的用法
[root@localhost opt]# cat testfile6
gd
god
good
goood
gooood
goooabcd
gooooood
gooooooodddd
abccba
abccba123
oooogooood
ooooogd
gold
goad
#查询一串字符中有goo*d字样,且o有0个或多个,此字符串可以不在开头或结尾
[root@localhost opt]# grep "goo*d" testfile6
god
good
goood
gooood
gooooood
gooooooodddd
oooogooood
#查询以g开头d结尾,中间的o有0个或多个
[root@localhost opt]# grep "^goo*d$" testfile6
god
good
goood
gooood
gooooood
[] [^]的用法
#查询一个字符,其中有一段以go开头d结尾,中间的o、l、a这几种字符中的一种
[root@localhost opt]# grep “go[ola]d” testfile6
good
gold
goad
#查询一个字符,其中有一段以go开头d结尾,中间的o、l、a这几种字符中的一个或多个
[root@localhost opt]# grep “go[ola]*d” testfile6
god
good
goood
gooood
gooooood
gooooooodddd
oooogooood
gold
goad
#匹配除了a-g开头的字符
[root@localhost opt]# grep "^[^a-g]" testfile6
oooogooood
ooooogd
\{n\} \{n,\} 的用法
#匹配good字符,其中\{2\}只会匹配前面的o两次
[root@localhost opt]# grep "go\{2\}d" testfile6
good
#匹配go..d,其中o至少2次及以上
[root@localhost opt]# grep "go\{2,\}d" testfile6
good
goood
gooood
gooooood
gooooooodddd
oooogooood
4.常见例题
电话例题
找出区号025开头的号码,且号码与区号间可以是空格、-、没有,号码必须是5或者8开头的八位数。
02588888888
025-5555555555
025 12345678
025 54321678
025ABC88888
025-85432109
028-85643210
0251-52765421
解题思路
先将电话拆分为3段,第一段找出区号,第二段筛选出号码与区号之间的分隔符,第三段号码后几位。
区号025开头。^是以什么为开头,用()将025作为一个整体
^(025)
号码与区号间可以是空格、-、没有。将题目要求的空格和-写入[],由于?是前面的子表达式0次或1次,0次就符合题目要求的没有
[ -]?
号码必须是5或者8开头的八位数。用[]确认是5或8数字开头的号码,然后再匹配0-9的7位数结尾的数
[58][0-9]{7}$
总体输出如下:
[root@localhost opt]# egrep "(025)[ -]?[58][0-9]{7}$" iphone.sh
02588888888
025 54321678
025-85432109
电子邮箱例题
根据 用户名@子域名.[二级域名].顶级域
格式找出符合要求的电子邮箱
zhangsan123@qq.com
li si@163.com
wang@wu@sina.com
zhao liu@126.com
qianqi@sina.com.cn
解题思路
将邮箱拆分为三段,第一段用户名,第二段子域名二级域,第三段顶级域
用户名@:长度要求在6-18位,任意大小写英文,任意数字,除了@符号和空格以外的其它任意符号字符,开头只能是 _ 或者字母
^([a-zA-Z_][^@ ]{5,17})@
子域名.[二级域名]:长度任意,符号只能包含 - _ .
[a-zA-Z0-9\_\-\.]+(\.[a-zA-Z0-9\_\-\.]+)?
.顶级域名: 长度在2-5,任意大小写英文
\.([a-zA-Z]{2,5})$
总体输出如下:
[root@localhost opt]# egrep "^([a-zA-Z_][^@ ]{5,17})@[a-zA-Z0-9\_\-\.]+(\.[a-zA-Z0-9\_\-\.]+)?\.([a-zA-Z]{2,5})$" ip.sh
zhangsan123@qq.com
qianqi@sina.com.cn
二、Shell常用命令
1.sort命令——排序工具
sort 是一个以行为单位对文件内容进行排序的工具,也可以根据不同的数据类型来排序。例如数据和字符的排序就不一样。
比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。
ASCII码
十进制 | 字符 | 十进制 | 字符 | 十进制 | 字符 | 十进制 | 字符 | 十进制 | 字符 |
---|---|---|---|---|---|---|---|---|---|
32 | | 51 | 3 | 70 | F | 89 | Y | 108 | l |
33 | ! | 52 | 4 | 71 | G | 90 | Z | 109 | m |
34 | " | 53 | 5 | 72 | H | 91 | [ | 110 | n |
35 | # | 54 | 6 | 73 | I | 92 | \ | 111 | o |
36 | $ | 55 | 7 | 74 | J | 93 | ] | 112 | p |
37 | % | 56 | 8 | 75 | K | 94 | ^ | 113 | q |
38 | & | 57 | 9 | 76 | L | 95 | _ | 114 | r |
39 | ' | 58 | : | 77 | M | 96 | `` ` | 115 | s |
40 | ( | 59 | ; | 78 | N | 97 | a | 116 | t |
41 | ) | 60 | < | 79 | O | 98 | b | 117 | u |
42 | * | 61 | = | 80 | P | 99 | c | 118 | v |
43 | + | 62 | > | 81 | Q | 100 | d | 119 | w |
44 | , | 63 | ? | 82 | R | 101 | e | 120 | x |
45 | - | 64 | @ | 83 | S | 102 | f | 121 | w |
46 | . | 65 | A | 84 | T | 103 | g | 122 | z |
47 | / | 66 | B | 85 | U | 104 | h | 123 | { |
48 | 0 | 67 | C | 86 | V | 105 | i | 124 | ` |
49 | 1 | 68 | D | 87 | W | 106 | j | 125 | } |
50 | 2 | 69 | E | 88 | X | 107 | k | 126 | ~ |
语法格式
sort [选项] 参数
cat file | sort 选项
常用选项
选项 | 含义 |
---|---|
-n | 按照数字进行排序。 |
-r | 反向排序。 |
-u | 等同于uniq ,表示相同的数据仅显示一行,即为去重。 |
-t | 指定字段分隔符,默认使用[Tab]健分隔。 |
-k | 指定排序字段。 |
-o <输出文件> | 将排序后的结果转存至指定文件。效果和重定向输出相同。 |
-f | 忽略大小写,会将小写字母都转换为大写字母来进行比较。 |
-b | 忽略每行前面的空格。 |
使用方式
字母排序:不加任何选项默认按第一列升序,字母的话就是从a到z由上而下显示
[root@localhost ~]# sort passwd.txt
abrt:x:173:173::/etc/abrt:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
chrony:x:992:987::/var/lib/chrony:/sbin/nologin
colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ip地址排序,按数字大小排序
[root@localhost ~]# cat ip.txt
192.168.145.45
192.168.145.12
192.168.145.33
192.168.145.22
192.168.145.1
[root@localhost ~]# sort -n ip.txt
192.168.145.1
192.168.145.12
192.168.145.22
192.168.145.33
192.168.145.45
ip地址反向排序
[root@localhost ~]# cat ip.txt
192.168.145.45
192.168.145.12
192.168.145.33
192.168.145.22
192.168.145.1
[root@localhost ~]# sort -nr ip.txt
192.168.145.45
192.168.145.33
192.168.145.22
192.168.145.12
192.168.145.1
ip地址排序,若出现ip有重复数字,可以使用-k选项
[root@localhost ~]# cat ip.txt
192.168.145.45
192.168.145.100
192.168.145.33
192.168.145.22
192.168.145.1
[root@localhost ~]# cat ip.txt | sort -t '.' -k 4 -n
192.168.145.1
192.168.145.22
192.168.145.33
192.168.145.45
192.168.145.100
将输结果不在屏幕上输出而是输出到指定文件
[root@localhost ~]# sort -n -t: -k 3 passwd.txt -o passwd.bak
[root@localhost ~]# cat passwd.bak
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
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
去掉文件中重复的行(-u等同于uniq)
[root@localhost ~]# cat abc.txt
apple
apple
orange
banana
banana
banana
pear
pear
[root@localhost ~]# sort -u abc.txt
apple
banana
orange
pear
2.uniq命令——去重工具
用于报告或者忽略文件中连续的重复行,常与 sort 命令结合使用
语法格式
uniq [选项] 参数
cat file | uniq 选项
注意:是连续的行,所以通常和sort结合使用先排序使之变成连续的行再执行去重操作,否则不连续的重复行他不能去重
常用选项
选项 | 含义 |
---|---|
-c | 进行计数,并删除文件中重复出现的行。 |
-d | 仅显示连续的重复行。 |
-u | 仅显示出现一次的行。 |
使用方式
统计重复行的次数
[root@localhost ~]# cat abc.txt | uniq -c #对连续重复的行进行统计
2 apple
1 pear
3 banana
1 orange
[root@localhost ~]# cat abc.txt | sort | uniq -c #先排序,在对重复行进行统计
2 apple
3 banana
1 orange
1 pear
结合sort去重
[root@localhost ~]# cat abc.txt | sort | uniq -d #仅显示重复行
apple
banana
[root@localhost ~]# cat abc.txt | sort | uniq -u #仅显示不重复的行
orange
pear
[root@localhost ~]# cat abc.txt | sort | uniq #去重
apple
banana
orange
pear
输出出现3次以上ip地址
[root@localhost ~]# vim ip.sh
#!/bin/bash
cat ip.txt | sort -n -t '.' -k4 | uniq -c > ./count.txt #在ip.txt文件中查找ip地址,并以点为分隔符的第四段进行排序以及统计重复行的次数一并输出至count.txt
IFSB=$IFS
IFS=$'\n'
for i in $ (cat ./count.txt)
do
num=$(echo $i | awk '{print $1}') #记录重复行的次数
if [ $num -eq 3 ] ;then #判断ip地址重复次数是否有等于3的
echo $i | awk '{print $2}' #如果有等于3的,输出第二个字段的ip地址
fi
done
IFS=$IFSB
[root@localhost ~]# bash ip.sh
192.168.145.33
192.168.145.45
#查找一分钟内三次登录系统输入密码错误的用户,并将该IP地址加入到黑名单/etc/hosts.deny中
[root@localhost ~]# vim demo3.sh
#!/bin/bash
count=$(cat /var/log/secure | grep 'Failed password' | awk '{print $11}' | sort -n -t '.' -k4 | uniq -c) #先通过grep过滤出secure文件中输入密码报错的字符行,然后通过分割过滤出每行的ip地址,接着将字段根据ip地址第四段进行排序并进行计数、删除重复行,将获取的值赋给count
IFSB=$IFS
IFS=$'\n' #修改for循环的IFS环境只以\n换行符进行分割
for i in $count
do
num=$(echo $i | awk '{print $1}' ) #获取重复行出现的次数
#echo $num #输出重复次数
if [ $num -gt 3 ];then #判断重复次数大于3次,输出第二字段的ip地址
IP=$(echo $i | awk '{print $2}' )
echo "sshd:$IP" >> /etc/hosts.deny
fi
done
IFS=$IFSB
[root@localhost ~]# bash demo3.sh
[root@localhost ~]# cat /etc/hosts.deny
sshd:192.168.145.30
3.tr命令——修改工具
常用来对来自标准输入的字符进行替换、压缩和删除。
语法格式
tr [选项] [参数]
常用选项
选项 | 含义 |
---|---|
-c | 保留字符集1的字符,其他的字符(包括换行符\n )用 字符集2 替换。 |
-d | 删除所有属于 字符集1 的字符。 |
-s | 将重复出现的字符串压缩为一个字符;用 字符集2 替换 字符集1。 |
-t | 字符集2 替换 字符集1 ,不加选项同结果。 |
使用方式
大小写字母的替换
[root@localhost ~]# echo abc | tr "a-z" "A-Z" #将abc字符中所有小写字母替换为大写字母
ABC
[root@localhost ~]# echo abc | tr "ac" "AC" #将abc字符中所有ac字母替换为AC字母
AbB
其他字符保留与替换,比如换行符
[root@localhost ~]# echo -e "ab\nadcd\nab" #正常输入一串字符,其中包含换行符
ab
adcd
ab
[root@localhost ~]# echo -e "ab\nadcd\nab" | tr -c "ab" "0" #将字符串中除了ab字符,其他所有字符都替换为0,可以看出换行符也替换为0了
ab0a0000ab0[root@localhost ~]#
[root@localhost ~]# echo -e "ab\nadcd\nab" | tr -c "ab\n" "0" #将字符串中除了ab以及换行符,其他所有字符都替换为0,可以看出换行符保留了,字符格式仍然存在
ab
a000
ab
删除指定字符
[root@localhost ~]# echo 'hello world' #正常输出一串字符
hello world
[root@localhost ~]# echo 'hello world' | tr -d ' ' #删除空格后的字符输出
helloworld
压缩连续重复的字符以及可以替换其字符
[root@localhost ~]# echo 'thhhhhhis iiisssss mmmmy firrrrrst wrrrrrrite'
thhhhhhis iiisssss mmmmy firrrrrst wrrrrrrite
[root@localhost ~]# echo 'thhhhhhis iiisssss mmmmy firrrrrst wrrrrrrite' | tr -s 'hismr'
this is my first write
[root@localhost ~]# echo 'thhhhhhis iiisssss mmmmy firrrrrst wrrrrrrite' | tr -s 'hismr' 'HISMR'
tHIS IS My fIRSt wRIte
排序脚本
[root@localhost ~]# vim demo4.sh
#!/bin/bash
read -p"请输入一个数组数:" num
arry=($num)
echo "排序前的数组的列表为: ${arry[@]}"
#先获取数组,然后通过tr将空格替换成换行符进行竖列排序,然后通过sort进行数字排序,最后再将换行符替换成空格以实现从小到大排序
arry1=(`echo ${arry[@]} | tr " " "\n"| sort -n | tr "\n" " "`)
echo "排序后的数组的列表为: ${arry1[@]}"
[root@localhost ~]# bash demo4.sh
请输入一个数组数:63 4 24 1 3 15
排序前的数组的列表为: 63 4 24 1 3 15
排序后的数组的列表为: 1 3 4 15 24 63
4.cut命令——截取工具
cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。
语法格式
cut 参数
cat file | cut 选项
常用选项
选项 | 含义 |
---|---|
-f | 通过指定哪一个字段进行提取。cut命令使用"TAB"作为默认的字段分隔符。 |
-d | "TAB"是默认的分隔符,使用此选项可以更改为其他的分隔符。 |
–complement | 此选项用于排除所指定的字段。 |
–output-delimiter | 更改输出内容的分隔符。 |
使用方式
筛选出指定多个字段
[root@localhost ~]# cat /etc/passwd | cut -d ":" -f 1,3
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
operator:11
games:12
ftp:14
nobody:99
systemd-network:192
dbus:81
筛选出指定多个字段,修改分隔符输出
[root@localhost ~]# cat /etc/passwd | cut -d ":" -f 1,3 --output-delimiter=","
root,0
bin,1
daemon,2
adm,3
lp,4
sync,5
shutdown,6
halt,7
mail,8
operator,11
games,12
ftp,14
nobody,99
systemd-network,192
dbus,81
5.split命令——拆分工具
split命令 用于linux系统下将一个大的文件拆分成若干小文件
语法格式
split 选项 参数 原始文件 拆分后文件名前缀
常用选项
选项 | 含义 |
---|---|
-l | 以行数拆分 |
-b | 以大小拆分 |
使用方式
[root@localhost opt]# split -l 20 ./CentOS-Vault.repo Vault #将CentOS-Vault.repo以20行一个文件进行拆分
[root@localhost opt]# ls
CentOS-Vault.repo Vaultab Vaultae Vaultah Vaultak Vaultan Vaultaq
rh Vaultac Vaultaf Vaultai Vaultal Vaultao
Vaultaa Vaultad Vaultag Vaultaj Vaultam Vaultap
[root@localhost opt]# cat -n Vaultaa
1 # CentOS Vault contains rpms from older releases in the CentOS-7
2 # tree.
3
4 # C7.0.1406
5 [C7.0.1406-base]
6 name=CentOS-7.0.1406 - Base
7 baseurl=http://vault.centos.org/7.0.1406/os/$basearch/
8 gpgcheck=1
9 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
10 enabled=0
11
12 [C7.0.1406-updates]
13 name=CentOS-7.0.1406 - Updates
14 baseurl=http://vault.centos.org/7.0.1406/updates/$basearch/
15 gpgcheck=1
16 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
17 enabled=0
18
19 [C7.0.1406-extras]
20 name=CentOS-7.0.1406 - Extras
[root@localhost opt]#
6.paste命令——合并工具
paste命令用于合并文件的列。
语法格式
paste [-s][-d <间隔字符>] 文件...
常用选项
选项 | 含义 |
---|---|
-d<间隔字符> | 用指定的间隔字符取代制表符 |
-s | 把多行内容合并为一行进行显示 |
使用方式
paste命令合并文件
[root@localhost opt]# paste adb.txt 123.txt #默认使用制表符分隔
aa 111
bb 222
cc 333
dd 444
[root@localhost opt]# paste -d "," adb.txt 123.txt #可以指定分隔符为逗号
aa,111
bb,222
cc,333
dd,444
[root@localhost opt]# paste -d "," -s adb.txt 123.txt #将每一列转换为行输出
aa,bb,cc,dd
111,222,333,444
输出两个文件的第二列至一个新文件中
[root@localhost opt]# cat 1.txt
a A
b B
c C
d D
e E
f F
[root@localhost opt]# cat 2.txt
1:10
2:20
3:30
4:40
5:50
6:60
#先合并两个文件,用空格替换制表符,然后将冒号分隔符替换为空格,最后通过空格截取第2、4字段输出至新文件
[root@localhost opt]# paste -d ' ' 1.txt 2.txt | tr -t ":" " " | cut -d " " -f "2,4" >> 12.txt
[root@localhost opt]# cat 12.txt
A 1
B 2
C 3
D 4
E 5
F 6
其他合并方式
case 文件1 文件2 >> 新文件
vim 文件 ——> 将光标移至最后一行 ——> :r ./当前目录文件
7.eval命令——两次扫描工具
命令字前加eval
时,shell会在执行命令之前扫描它两次。eval命令将首先会先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实现其功能的变量,该命令对变量进行两次扫描。
语法格式
eval 命令序列
使用方式
[root@localhost opt]# vim test1.sh
#!/bin/bash
a=100
b=a
eval echo \$$b #先扫描$b,因为b=a,所以b=100,然后再次扫描,\$意为$本身,最后为echo $b,输出值为100
eval $b=50 #先扫描$b,因为b=a,所有$a=50,最后为echo $a,输出值为50
echo $a
[root@localhost opt]# bash test1.sh
100
50