一.case语句
case语句为多选择语句.可以用case语句匹配一个值与一个模式,如果匹配成功,执行相
匹配的命令.
case var in 定义变量;var代表是变量名
pattern 1) 模式1;用 | 分割多个模式,相当于or
command1 需要执行的语句
;; 两个分号代表命令结束
pattern 2)
command2
;;
pattern 3)
command3
;;
*) default,不满足以上模式,默认执行*)下面的语句
command4
;;
esac esac表示case语句结束
案例1
- 脚本提示让用户输入需要管理的服务名,然后提示用户需要对服务做什么操作,如启动,关闭,重启等
[root@shell ~]# vim case.sh
#!/bin/bash
read -p "请输入要操作的服务名称(nginx):" service
read -p "请输入要对服务执行的操作:" action
case $action in
start|S)
systemctl start $service
echo "$service is running"
;;
stop|T)
systemctl stop $service
echo "$service is stoped"
;;
restart|R)
systemctl restart $service
echo "$service is restart"
;;
*)
echo "请输入正确的操作指令"
;;
esac
[root@shell ~]# source case.sh
请输入要操作的服务名称(nginx):vsftpd
请输入要对服务执行的操作:restart
vsftpd is restart
[root@shell ~]# source case.sh
请输入要操作的服务名称(nginx):nginx
请输入要对服务执行的操作:status
请输入正确的操作指令
案例2
- 模拟一个多任务维护界面.当执行程序时先显示总菜单,然后进行选择后做相应维护监控操作.
[root@shell ~]# vim case2.sh
#!/bin/bash
cat <<-EOF
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
EOF
# <<-EOF将忽略起止内容中前面的tab制表符,而<<EOF将不会
while true
do
read -p "请输入需要的选项:" var1
case $var1 in
h)
cat <<-EOF
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
EOF
;;
f)
fdisk -l
;;
d)
df -h
;;
m)
free -m
;;
u)
untime
;;
q)
echo "已退出程序"
break
;;
esac
done
[root@shell ~]# source case2.sh
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
请输入需要的选项:u
16:33:40 up 2 days, 18 min, 1 user, load average: 0.01, 0.02, 0.00
请输入需要的选项:^C
[root@shell ~]# source case2.sh
h 显示命令帮助
f 显示磁盘分区
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
请输入需要的选项:u
16:33:44 up 2 days, 18 min, 1 user, load average: 0.01, 0.02, 0.00
请输入需要的选项:q
已退出程序
二.函数
shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数.给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能.
1.函数定义
函数名()
{
函数体(一堆命令的集合,来实现某个功能)
}
function 函数名()
{
函数体(一堆命令的集合,来实现某个功能)
}
function_name() {
command
command
}
function function_name() {
command
command
}
函数中return说明:
1.return可以结束一个函数,类似于前面讲的循环控制语句break(结束当前循环,执行循环体后面的代码)
2.return默认返回函数中最后一个命令的退出状态,也可以给定参数值,该参数值的范围是0-256之间.
3.如果没有return命令,函数将返回最后一个Shell的退出值.
2.函数的调用
- 当前命令行调用
[root@shell-note ~]# vim fun1.sh
hello(){
#!/bin/bash
hello(){
echo "hello xiaomei $1"
}
menu(){
cat <<-EOF
1. mysql
2. web
3. app
4. exit
EOF
}
[root@shell-note ~]# source fun1.sh
# 生效函数
[root@shell-note ~]# hello 111
# 调用函数
hello xiaomei 111
[root@shell-note ~]# menu
1. mysql
2. web
3. app
4. exit
- 定义到用户的环境变量中
[root@shell-note ~]# vim .bashrc
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# 添加如下内容
hello(){
echo "hello xiaomei $1"
}
menu(){
cat <<-EOF
1. mysql
2. web
3. app
4. exit
EOF
}
[root@shell-note ~]# source .bashrc
# 生效函数
[root@shell-note ~]# hello 111
hello xiaomei 111
[root@shell-note ~]# menu
1. mysql
2. web
3. app
4. exit
- 脚本中调用
[root@shell-note ~]# vim fun2.sh
#!/bin/bash
menu(){
cat <<-EOF
h hello
q quit
t test
EOF
}
menu
# 调用函数
[root@shell-note ~]# source fun2.sh
h hello
q quit
t test
3.应用案例
通过跳板机连接生产机器
结合expect脚本
[root@shell-note ~]# dnf -y install expect
[root@shell-note ~]# vim jump-server.sh
#!/bin/bash
while true
do
menu(){
cat <<-EOF
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
EOF
}
menu
read -p "请选择你要操作的主机:" host
case $host in
1)
./1.sh
;;
2)
./2.sh
;;
3)
./3.sh
;;
4)
./4.sh
;;
h)
menu
;;
q)
break
;;
esac
done
[root@shell-note ~]# vim 1.sh
#!/usr/bin/expect
spawn ssh root@172.20.251.124
# 启动新的进程
# 其余脚本皆为修改此处ip即可
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "000000\r" };
}
# expect用于从进程接受字符串
# send用于向进程发送字符串
interact
# 允许用户交互
[root@shell-note ~]# chmod +x {1..4}.sh
# 增加expect脚本执行权限
[root@shell-note ~]# sed -i "/expect {/i\set timeout 30" {1..4}.sh
# 添加超时处理
[root@shell-note ~]# cat 1.sh
#!/usr/bin/expect
spawn ssh root@172.20.251.124
# 启动新的进程
# 其余脚本皆为修改此处ip即可
set timeout 30
expect {
"yes/no" { send "yes\r"; exp_continue }
"password:" { send "000000\r" };
}
# expect用于从进程接受字符串
# send用于向进程发送字符串
interact
# 允许用户交互
[root@shell-note ~]# source jump-server.sh
# 测试脚本
欢迎使用Jumper-server,请选择你要操作的主机:
1. DB1-Master
2. DB2-Slave
3. Web1
4. Web2
h. help
q. exit
请选择你要操作的主机:4
spawn ssh root@172.20.251.164
root@172.20.251.164's password:
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Fri Sep 16 08:51:27 2022 from 172.20.251.192
[root@shell ~]#
# 成功登录生产服务器
实战不推荐,仅当练手项目,因为密码暴露在脚本中不是安全的
四.正则表达式
1.什么是正则表达式
正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。
许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。
正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。
支持正则表达式的程序如:locate |find| vim| grep| sed |awk
2.第一类正则
- 名词解释:
元字符:指那些在正则表达式中具有特殊意义的专用字符,如:点(.) 星(*) 问号(?)等
前导字符:即位于元字符前面的字符 abc* aooo.
- 正则中常用的元字符
(1). 任意单个字符,除了换行符
(2)* 前导字符出现0次或连续多次 ab*能匹配“a”,“ab”以及“abb”,但是不匹配“cb”
(3).* 任意长度的字符 ab.* ab123 abbb abab
(4)^ 行的开头
(5)$ 行的结尾
(6)^$ 空行
(7)[] 匹配指定字符组内的任一单个字符 [abc]
(8)[^] 匹配不在指定字符组内的任一字符 [^abc]
(9)^[] 匹配以指定字符组内的任一字符开头 ^[abc]
(10)^[^] 匹配不以指定字符组内的任一字符开头 ^[^abc]
(11)\< 取单词的头
(12)\> 取单词的尾
(13)\<\> 精确匹配符号 grep -w 'xxx'
(14)\{n\} 匹配前导字符连续出现n次 go\{2\} google gooogle
(15)\{n,\} 匹配前导字符至少出现n次
(16)\{n,m\} 匹配前导字符出现n次与m次之间
(17) \(strings\) 保存被匹配的字符
[root@shell-note ~]# vim 1.txt
172.20.251.1
:%s/\(172.20.251\).1/\1.254/g
# 替换172.20.251.1为172.20.251.254
172.20.251.254
# sed -n 's#\(192\.168\)\.0\.254#\1\.1\.254#p'
找出含有192.168的行,同时保留192.168并标记为标签1,之后可以使用\1来引用它。最多可以定义9个标签,从左边开始编号,最左边的是第一个。
\1 就代表被匹配到的第一个模式,sed 一共可以记录9个模式。
[root@shell-note ~]# sed -n "s/\(192.168.10\).1/\1.254/p" 1.txt
192.168.10.254
[root@shell-note ~]# sed -n "s/\(192.168\).10.1/\1.254/p" 1.txt
192.168.254
将you are the hero 替换为we are family
[root@shell-note ~]# vim 1.txt
10.1.1.254
192.168.10.1
you are hero
:%s/you \(are\) the hero/we \1 \2family/p
we are family
# 同理,使用sed可替换为如下命令
[root@shell-note ~]# sed -n "s/you \(are\) the hero/we \1 family/p" 1.txt
we are family
[root@shell-note ~]# sed -n "s/you are the hero/we are family/p" 1.txt
we are family
# -n为只显示匹配行,p将结果打印出来
# 如果要改变文件内容使用i参数替换
[root@shell-note ~]# sed -i "s/you \(are\) the hero/we \1 family/g" 1.txt
[root@shell-note ~]# cat 1.txt
10.1.1.254
192.168.10.1
we are family
# 此处不使用-r参数,因为-r代表使用扩展正则表达式
[0-9] [a-z] [A-Z] [a-zA-Z] [a-Z]
=================================================================================
Perl内置正则:
\d 匹配数字 [0-9]
\w 匹配字母数字下划线[a-zA-Z0-9_]
\s 匹配空格、制表符、换页符[\t\r\n]
#grep -P '\d' test.txt
#grep -P '\w' test.txt
#grep -P '\s' test.txt
[root@shell-note ~]# grep -P "\d" 1.txt
10.1.1.254
192.168.10.1
[root@shell-note ~]# grep -P "\w" 1.txt
10.1.1.254
192.168.10.1
you are the hero
[root@shell-note ~]# grep -P "\s" 1.txt
you are the hero
- 扩展类的正则表达式 grep -E 或则 egrep
扩展正则表达式元字符
+ 匹配一个或多个前导字符 bo+ boo bo
? 匹配零个或一个前导字符 bo? b bo
a|b 匹配a或b
() 组字符 hello myself yourself (my|your)self
{n} 前导字符重复n次 \{n\}
{n,} 前导字符重复至少n次 \{n,\}
{n,m} 前导字符重复n到m次 \{n,m\}
[root@shell-note ~]# grep '[0-9]\{2\}\.[0-9]\{1\}\.[0-9]\{1\}\.[0-9]\{1\}' 1.txt
10.1.1.1
[root@shell-note ~]# grep -E '[0-9]{2}\.[0-9]{1}\.[0-9]{1}\.[0-9]{1}' 1.txt
10.1.1.1
[root@shell-note ~]# grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' 1.txt
10.1.1.1
192.168.10.1
[root@shell-note ~]# grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' 1.txt
10.1.1.1
192.168.10.1
3.第二类正则
表达式 | 功能 | 示例 |
---|---|---|
[:alnum:] | 字母与数字字符 | [[:alnum:]]+ |
[:alpha:] | 字母字符(包括大小写字母) | [[:alpha:]]{4} |
[:blank:] | 空格与制表符 | [[:blank:]]* |
[:digit:] | 数字 | [[:digit:]]? |
[:lower:] | 小写字母 | [[:lower:]]{4,} |
[:upper:] | 大写字母 | [[:upper:]]+ |
[:punct:] | 标点符号 | [[:punct:]] |
[:space:] | 包括换行符,回车等在内的所有空白 | [[:space:]]+ |
[root@shell-note ~]# grep -E '^[[:digit:]]+' 1.txt
10.1.1.1
192.168.10.1
[root@shell-note ~]# grep -E '^[^[:digit:]]+' 1.txt
you are the hero
[root@shell-note ~]# grep -E '[[:lower:]]{4,}' 1.txt
you are the hero
4.实践操作
[root@shell-note ~]# vim test.txt
1111111111
2222222222
2022-09-20
helloworld
welcome to test.
192.168.10.254
10.1.1.20
AI2test
S1mple
tbase
123@qq.com
abc
123456
实现如下要求:
1.查找不以大写字母开头的行
2.查找有数字的行(两种写法)
3.查找一个字母和一个数字连起来的
4.查找不以t开头的行
5.查找以数字开头的
6.查找以大写字母开头的
7.查找以小写字母开头的
8.查找以点结束的
9.去掉空行
10.去掉带空格的空行
11.查找完全匹配123456的行
12.查找ip并将最后的数字都替换为254
13.查找hello开头的行并将之后内容替换为program
14.统计/sbin/nologin在/etc/passwd里出现了几次
15.找出全部是数字的行
16.使用正则表达式给仅有数字行前加两0
17.查找邮箱账号
答案例(不止一种方法,结果正确即可)
1.
[root@shell-note ~]# grep "^[^A-Z]" test.txt
2.
[root@shell-note ~]# grep "[0-9]" test.txt
[root@shell-note ~]# grep -E "[[:digit:]]+" test.txt
3.
[root@shell-note ~]# grep "[A-Za-z][0-9]" test.txt
4.
[root@shell-note ~]# grep "^[^t]" test.txt
5.
[root@shell-note ~]# grep "^[^0-9]" test.txt
6.
[root@shell-note ~]# grep "^[A-Z]" test.txt
7.
[root@shell-note ~]# grep "^[a-z]" test.txt
8.
[root@shell-note ~]# grep "\.$" test.txt
# 记得给点加上转义字符
9.
[root@shell-note ~]# sed -i "/^$/d" test.txt
10.
[root@shell-note ~]# sed -i "/^\s*$/d" test.txt
11.
[root@shell-note ~]# grep "123456" test.txt
123456
12.
[root@shell-note ~]# sed -n "s/\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).[0-9]\{1,3\}/\1.254/p" test.txt
# 此处只为显示ip替换后的结果
# 下面的命令才是替换文本中的ip内容
[root@shell-note ~]# sed -i "s/\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).[0-9]\{1,3\}/\1.254/g" test.txt
13.
[root@shell-note ~]# sed -n "s/\(^hello\).*/\1program/p" test.txt
[root@shell-note ~]# sed -i "s/\(^hello\).*/\1program/g" test.txt
14.
[root@shell-note ~]# grep -c "/sbin/nologin" /etc/passwd
15.
[root@shell-note ~]# grep -x "[0-9]*" test.txt
# -x 参数会查找字符串 exact 的匹配,即全字匹配
16.
[root@shell-note ~]# sed -n "s/\(^[0-9][0-9]*[0-9]$\)/00\1/p" test.txt
001111111111
002222222222
00123456
17.
[root@shell-note ~]# grep "[0-9]*@[a-z0-9]*\.[a-z]*" test.txt
[root@shell-note ~]# grep -E '^[0-9]+@[a-z0-9]+\.[a-z]+$' test.txt
# grep参数详解
grep --help:
匹配模式选择:
Regexp selection and interpretation:
-E, --extended-regexp 扩展正则
-G, --basic-regexp 基本正则
-P, --perl-regexp 调用perl的正则
-e, --regexp=PATTERN use PATTERN for matching
-f, --file=FILE obtain PATTERN from FILE
-i, --ignore-case 忽略大小写
-w, --word-regexp 匹配整个单词
5.正则总结
元字符:在正则中,具有特殊意义的专用字符 . *
前导字符:元字符前面的字符叫前导字符
元字符 | 字符说明 | 示例 |
---|---|---|
* | 前导字符出现0次或者连续多次 | ab* abbbb |
. | 除了换行符以外,任意单个字符 | ab. ab8 abu |
.* | 任意长度的字符 | ab.* adfdfdf |
[] | 括号里的任意单个字符或一组单个字符 | [abc][0-9][a-z] |
[^] | 不匹配括号里的任意单个字符或一组单个字符 | [^abc] |
^[] | 匹配以括号里的任意单个字符开头 | ^[abc] |
^[^] | 不匹配以括号里的任意单个字符开头 | ^[^abc] |
^ | 行的开头 | ^root |
$ | 行的结尾 | bash$ |
^$ | 空行 | |
\{n\}和{n} | 前导字符连续出现n次 | [0-9]\{3\} |
\{n,\}和{n,} | 前导字符至少出现n次 | [a-z]{4,} |
\{n,m\}和{n,m} | 前导字符连续出现n-m次 | go{2,4} |
\<\> | 精确匹配单词 | \<hello\> |
\(\) | 保留匹配到的字符 | \(hello\) |
+ | 前导字符出现1次或者多次 | [0-9]+ |
? | 前导字符出现0次或者1次 | go? |
| | 或 | ^root|^ftp |
() | 组字符 | (hello|world)123 |
\d | perl内置正则 | grep -P \d+ |
\w | 匹配字母数字下划线 |