【LinuxShell】Shell编程之正则表达式


引言

  在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

一、正则表达式

1.正则表达式概述

  正则表达式通常用于判断语句中,用来检查某一字符串是否满足某一格式。

  正则表达式是由普通字符元字符组成。普通字符包括小写字母、数字、标点符号及一些其他符号。元字符是指在正则表达式中具有特殊意义的专用字符,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。

2.正则表达式的分类

  正则表达式根据从POSIX BRE或者POSIX ERE标准可以分为基本正则表达式扩展正则表达式

基本正则表达式

支持的工具:grepegrepsed awk,注意grep要配合-E或者-P使用。

元字符含义及用法
\转义字符,用于取消特殊符号的含义,例: \!\n\$
^匹配字符串开始的位置,例:^a^the^#^[a-z]
$匹配字符串结束的位置,例: word$^$匹配空行
.匹配除\n之外的任意的一个字符,例: go.dg..d。如果想要匹配包含\n字符可以使用 [.\n]
*匹配前面子表达式0次或者多次,例: goo*dgo.*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\}匹配两位到三位数字
注: egrepawk使用{n}{n,}{n,m}匹配时 {} 前不用加 \
\w
\W
匹配包括下划线的任何单词字符。
匹配任何非单词字符。等价于[^A-Za-z0-9_]
\d
\D
匹配一个数字字符。
匹配一个非数字字符。等价于[^0-9]
\s
\S
空白符。
非空白符。

扩展正则表达式

支持的工具:egrepawk,注意:使用grep要配合-E或者-P使用,sed要配合-r使用。

元字符含义及用法
+匹配前面子表达式1次以上,例: go+d,将匹配至少一个o,如godgoodgoood
?匹配前面子表达式0次或者1次,例: go?d,将匹配gdgod
()将括号中的字符串作为一个整体,例1: g(oo)+d,将匹配oo整体1次以上,如goodgooood
|以或的方式匹配字符串,例: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 51370F89Y108l
33!52471G90Z109m
34"53572H91[110n
35#54673I92\111o
36$55774J93]112p
37%56875K94^113q
38&57976L95_114r
39'58:77M96`` `115s
40(59;78N97a116t
41)60<79O98b117u
42*61=80P99c118v
43+62>81Q100d119w
44,63?82R101e120x
45-64@83S102f121w
46.65A84T103g122z
47/66B85U104h123{
48067C86V105i124`
49168D87W106j125}
50269E88X107k126~

语法格式

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
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我的宝贝大唐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值