第
5
章 正则表达式
知识要点
select工具
通配符
grep命令
基础正则表达式
扩展正则表达式
shell中特殊字符总结
作用:匹配文本
select
工具
select是bash自带的字符菜单工具
不需要echo命令就可以自动列出菜单
不需要read命令就可以读取变量的值
不需要赋值命令就可以自动赋值给变量
基本语法
PS3="select的提示符"
select variable in list
do
commands
done
select
脚本示例
select配置case语句实现字符菜单
PS3=“请输入选项: " #select的提示符
select number in “自动安装LAMP论坛” “自动卸载LAMP论坛” “退出菜单"
do
case $number in
“自动安装LAMP论坛”)
install;;
“自动卸载LAMP论坛”)
uninstall;;
“退出菜单")
break;;
*)
echo -e "\n"
echo “不好意思没有这个选项";;
esac
done
clear
通配符
通配符(globbing)
最常用的通配符包括:?、*、[]、{}、^等,通配符与正则表达式中的元字符意义不完全相同
- * 匹配0个或者多个字符(任意数目)
- ? 匹配1个字符
- […] 匹配范围内任意1个字符 [az]、[a-z]、[a\-z]
- [^…] 匹配范围外任意1个字符,表示取反
- {} 组合匹配,touch a{1,3,5} touch b{1..10} touch {a,b,c}_{1,2,3}
搜索文本:
grep
grep通用正则表达式分析程序(global search regular expression and printing)
- 用途:使用正则表达式搜索文本,并把匹配的行打印出来
- 格式:grep [选项]... 模式 目标文件
- -v: 反转查找,输出与模式不相符的行
- -An:同时显示符合条件行的下面n行
- -Bn:同时显示符合条件行的上面n行
- -Cn:同时显示符合条件行的上面和下面n行
- -E: 支持扩展正则表达式
- -o: 仅显示匹配模式的字符串
- -f: 根据文件内容进行匹配
Linux系统支持三种形式的grep命令,通常将这三种形式的grep命令称为grep命令族,这三种形式具体为
- ls /bin/*grep
- fgrep:不支持正则表达式,快速搜索简单模式,按照字符串的字面意思进行匹配吗,相当于grep -F
- grep:可以使用基本正则表达式搜索
- egrep:可以使用基本和扩展正则表达式搜索,相当于grep -E
正则表达式介绍
正则表达式是一个指定文本模式的标准Unix 语法
- 使用特殊元字符实现复杂的搜索问题
- 元字符(metacharacters)是用来阐释字符表达式意义的字符,简言之,元字符就是描述字符的字符,它用于对字符表达式的内容、转换及各种操作信息进行描述。
正则表达式是由一串字符和元字符构成的字符串,简称RE(Regular Expression)
基本正则表达式和Unix兼容
扩展正则表达式增加了一些新的元字符
正则表达式由下列元素构成
普通字符,a、b 、1、2
通配符,与文件名通配符不是一回事
修饰符:”*”、”?”等
锚点:以什么开头、以什么结尾
通配符
- “.”:表示一定有一个任意字符
a…b表示什么意思?(ab之间有三个字符,例如:a123b)
- 方括号表达式:一个文字字符域
[abc]表示什么意思?(多选一)
[^abc]表示什么意思?(非 取反)
[0-9]、[a-z]、[A-Z]
- 域表达式和字符类
- 考虑到不同的编码方案推荐使用字符类方式
[:alnum:]-
字母数字混排
[:digit:]-数字
[:lower:]-小写字母
[:upper:]-大写字母
[:space:] -空白字符,空格、TAB、换行符等
[:alpha:]-字母
通用修饰符
- “?”:表示0个或者1个前面的字符(扩展)
ab?c表示什么意思?(ac之间
最多一个
b 例如:ac,abc)
- “*”:表示0个或者多个前面的字符
ab*c表示什么意思?(ac之间
0个或者多个b
,例如)
- “+”:表示1个或者多个前面的字符(扩展)
ab+c表示什么意思?(ac之间
最少一个
b)
- {n}:表示n个前面的字符
ab{2}c表示什么意思?(abbc,d的个数确定)
- {n,m}:表示n个到m个前面的字符,{4,}最少四个{,100}最多100个
ab{2,4}c表示什么意思?
.*表示什么意思?
锚点搜索
“^”:表示以什么开头行
^#表示什么意思?
grep -v ‘^#’ /etc/inittab | grep –v ^$
egrep ‘^[^[:digit:]]’ /ec/inittab 以非数字开头
“$”:表示以什么结尾的行
bash$表示什么意思?
egrep ':$' /etc/inittab
egrep ‘^hello$' file
\<:表示词首部
\>:表示词尾部
\< abc\>:表示abc这个单词
egrep ‘\' /usr/share/dict/words
扩展正则表达式
egrep、awk和Perl等Linux工具还支持正则表达式扩展出来的一些元字符,这些元字符如下表所示
符号
|
意义
|
?
|
匹配
0
个或
1
个在其之前的那个普通字符
|
+
|
匹配
1
个或多个在其之前的那个普通字符
|
()
|
表示一个字符集合
|
|
|
表示“或”意义,匹配一组可选的字符
|
扩展正则表达式介绍
正则表达式分组
“?”、”*”、”+”默认只能修饰前面一个字符
利用圆括号()可以实现多个字符分组
f(oo)*表示什么意思
在圆括号中利用”|”实现或者的功能
(oo|ee){2}表示什么意思
转义元字符
egrep ‘cat.' /etc/aa
egrep ‘cat\.' /etc/aa
正则表达式和通配符
正则表达式与通配符匹配的区别
-
- 正则表达式只在少数搜索和替换文本命令中使用
- 文件名匹配在bash中匹配文件名
- 都使用”*”、”?”但意义不一样
- 正则表达式元字符要放在引号内,避免bash Shell解释
疑难问题
匹配email地址
egrep "[0-Z._]+@[0-Z]+\.[a-Z]{2,3}"
匹配HTTP URL
egrep "http://[a-Z0-9.]+\.[a-Z]{2,3}"
egrep "http://[[:alnum:].]+\.[[:alpha:]]{2,3}"
shell
中的特殊字符
:冒号
内置的空命令,返回值为0
;分号
连续运行命令
| 管道
前面命令的标准输出作为后面命令的标准输入
正则中表示或者
&
将命令放到后台执行
表示标准输出和标准错误输出
&&
前面命令返回值为0才执行后面的命令
||
前面命令返回值为非0才执行后面的命令
# 井号
表示注释
? 问号
通配符中表示任意1个字符
正则表达式中表示0个或者1个前面的字符
* 星号
通配符中表示0个到多个任意字符
正则表达式中表示0个或者多个前面的字符
算术运算中的乘法
!惊叹号
将命令或者条件表达式的返回值取反
执行历史命令
vi或者ftp中执行外部shell命令
间接引用变量
$ 美元符号
取变量的值
正则表达式表示行尾
\ 反斜杠
单字符转义
> 大于号
输出重定向
条件测试中的大于号
< 小于号
输入重定向
条件测试中的小于号
= 等号
变量赋值
条件测试中的等号
+ 加号
算术运算中的加号
正则表达式中1个或多个前面的字符
>>
输出重定向追加
<<
here document
- 减号
算术运算中的减号
命令的选项
上一次工作目录
通配符和正则表达式中表示范围[a-z]
tar -cvf - /home | tar -xvf - 表示输出流或输入流
‘’ 单引号
解决变量赋值空格的问题
阻止shell替换
“” 双引号
解决变量赋值空格的问题
阻止shell部分字符替换,对$、!等无效
·· 反引号$()
命令行替换
% 百分号
算术运算中的模运算
vi中替换操作中表示所有行
() 单圆括号
子shell中执行命令,会继承父shell的变量
括起数组元素
(()) 双圆括号
算术运算
整数比较测试
[] 单方括号
通配符和正则中表示匹配括号中的任意一个字符
条件测试表达式
数组中下标括号
[[]] 双方括号
字符串比较测试
. 句点号
正则中表示任意1个字符
当前shell执行脚本命令
表示当前目录
{} 大括号
通配符扩展 abc{1,2,3}
正则表达式中表示范围
匿名函数{cmd1;cmd2;cmd3} &> /dev/null
括起变量名${abc}a
/ 正斜杠
算术运算中的除法
根目录或路径分割符
^
在[^abc]通配符中表示取反
在正则表达式中表示以什么开头
expect
自动交互的方法:
1、查看命令,看看有没有选项用来实现自动交互的。
[root@S1 ~]# echo "123" | passwd --stdin u1
Changing password for user u1.
passwd: all authentication tokens updated successfully.
2、输入重定向
passwd u1 < /tmp/p.txt
Changing password for user u1.
New password: BAD PASSWORD: it is WAY too short
BAD PASSWORD: is too simple
Retype new password: passwd: all authentication tokens updated successfully.
3、here document
[root@S1 ~]# passwd u1 << eof
> 123
> 123
> eof
Changing password for user u1.
New password: BAD PASSWORD: it is WAY too short
BAD PASSWORD: is too simple
Retype new password: passwd: all authentication tokens updated successfully.
4、用expect来实现
安装expect
[root@S1 Packages]# rpm -ivh expect-5.44.1.15-5.el6_4.x86_64.rpm tcl-devel-8.5.7-6.el6.x86_64.rpm tcl-8.5.7-6.el6.x86_64.rpm
warning: expect-5.44.1.15-5.el6_4.x86_64.rpm: Header V3 RSA/SHA1 Signature, key ID c105b9de: NOKEY
Preparing... ########################################### [100%]
1:tcl ########################################### [ 33%]
2:expect ########################################### [ 67%]
3:tcl-devel ########################################### [100%]
expect 完成自动交互的任务
[root@mysqlserver01 scripts]# rpm -qa | grep "expect"
expect-5.44.1.15-5.el6_4.x86_64
expect内部命令:
spawn: 后面加上需要执行的shell命令,比如说spawn ssh [email protected]
expect: 只有spawn 执行的命令结果才会被expect 捕捉到,因为spawn 会启
动一个进程,只有这个进程的相关信息才会被捕捉到。
send:send 会将expect 脚本中需要的信息发送给spawn 启动的那个进程
send_user: 只在屏幕显示,不送给spawn 启动的那个进程,相当于echo
定义变量:
set
例如:
set passwd "mypasswd"
set timeout 60
$argc 参数个数 相当于bash的$#
$argv 数组,存放所有参数 类似于bash的$@
如果需要在shell脚本中嵌套expect代码,就要使用expect -c "expect代码"
例如:
expect -c "
spawn ssh $user_name@$ip_addr df -P
expect {
\"*(yes/no)?\" {send \"yes\r\" ; exp_continue}
\"*password:\" {send \"$user_pwd\r\" ; exp_continue}
}
"
##################################################
#!/usr/bin/expect
set timeout 60
set ip_addr [lindex $argv 0]
set username [lindex $argv 1]
set user_pwd [lindex $argv 2]
set cmd_line [lindex $argv 3]
if {$argc != 4} {
send_user "usage: ./auto_login ip username password command\n"
exit
}
spawn ssh $username@$ip_addr $cmd_line
expect {
"(yes/no)?" {
send "yes\r"
exp_continue
}
"password:" {
send "$user_pwd\r"
exp_continue
}
}
总结:
自动交互的方法:
1、查找帮助,看有没有选项实现自动交互
2、用输入重定向能不能实现
3、用here document能不能实现
4、用expect能不能实现
案例
实验案例
1
显示文件中的所有A类地址。
egrep --color ‘^([1-9]|[1-9][0-9]|1[01][0-9]|12[0-6])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$ ' file
显示文件中的所有B类地址。
egrep --color ' ^(12[89]|1[3-8][0-9]|19[01])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$ ' file
显示文件中的所有C类地址。
egrep --color ' ^(19[2-9]|2[01][0-9]|22[0-3])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$’ file
实验案例
2
编写判断IP地址是否合法的脚本
有一个ip地址列表的文件
要求判断文件中的ip地址是否是合法的ipv4地址
只显示出文件中合法的ip地址
[root@localhost test]# bash test.sh
文件中合法的ip地址如下所示
1.168.1.16
223.10.10.1
192.168.100.19
1.18.1.20
20.20.20.20
实验案例
3
编写脚本实现显示当前主机eth接口的有效IP和有效网关,要求显示结果如下图所示(多使用正则表达式,少用cut和tr)
实验案例
4
编写修改IP脚本,要求如下:
输入当前IP
输入新IP和子网掩码
校验IP的合法性
立即生效和永久生效
修改失败要恢复原IP
不使用sed