case语句

case语句为多选择语句。

可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

case $var in            ;var
pattern 1) 1 |
command1
;;
pattern 2)
command2
;;
pattern 3)
command3
;;
*) default*)
command4
;;
esac esaccase

应用案例1——熟悉case语句的基本语法结构

1、当给程序传入start、stop、reload三个不同参数时分别执行相应命令。

#!/bin/bash
case $1 in
start|S)
echo "service is running...."
;;
stop|T)
echo "service is stoped..."
;;
reload|R)
echo "service is restart..."
;;
*)
echo "请输入你要的动作"
;;
esac





#!/bin/bash
read -p "请输入你要的动作:" action
case $action in
start|S)
echo "service is running...."
;;
stop|T)
echo "service is stoped..."
;;
reload|R)
echo "service is restart..."
;;
*)
echo "请输入你要的动作"
;;
esac

2、脚本提示让用户输入需要管理的服务名,然后提示用户需要对服务做什么操作,如启动,关闭,重启等

#!/bin/bash
read -p "请输入需要管理的服务名称(vsftpd):" service
case $service in
vsftpd)
read -p "请输入要操作的动作:" action
case $action in
start|S)
service vsftpd start
;;
stop|P)
service vsftpd stop
;;
reload|restart|R)
service vsftpd reload
;;
esac
;;
httpd)
echo "apache is running..."
;;
*)
echo "请输入需要管理的服务名称(vsftpd):"
;;
esac

应用案例2——菜单打印

模拟一个多任务维护界面。

当执行程序时先显示总菜单,然后进行选择后做相应维护监控操作。

总菜单

  h 
f
d
m 使
u
q 退

分析

1.   echo cat

[root@bobilinux shell]# cat case.sh
#!/bin/bash
echo -e "h 显示命令帮助\nf 显示磁盘分区\nd 显示磁盘挂载\nm 查看内存使用\nu 查看系统负载\nq 退出程序"
[root@bobilinux shell]# chmod +x case.sh
[root@bobilinux shell]# ./case.sh
h
f
d
m 使
u
q 退

[root@bobilinux shell]# cat case.sh
#!/bin/bash
#echo -e "h 显示命令帮助\nf 显示磁盘分区\nd 显示磁盘挂载\nm 查看内存使用\nu 查看系统负载\nq 退出程序"
cat <<-EOF
h
f
d
m 使
u
q 退
EOF #EOF前要有制表符(tab),如果上面的EOF前面没有-,那这里的EOF要顶格写
[root@bobilinux shell]# ./case.sh
h
f
d
m 使
u
q 退


2. read
3. case

脚本

#!/bin/bash
#打印菜单
cat <<-EOF
h
f
d
m 使
u
q 退
EOF

#让用户输入需要的操作
read -p "请输入需要操作的选项[h help]:" option
case $option in
h)
cat <<-EOF
h
f
d
m 使
u
q 退
EOF
;;
f)
fdisk -l
;;
d)
df -h
;;
m)
free -m
;;
u)
uptime
;;
q)
exit
;;
esac

执行结果

[root@bobilinux shell]# ./case.sh 
h
f
d
m 使
u
q 退
[h help]:h
h
f
d
m 使
u
q 退
[root@bobilinux shell]# ./case.sh
h
f
d
m 使
u
q 退
[h help]:m
total used free shared buffers cached
Mem: 1861 173 1688 0 46 36
-/+ buffers/cache: 90 1771
Swap: 999 0 999
[root@bobilinux shell]# ./case.sh
h
f
d
m 使
u
q 退
[h help]:u
12:17:47 up 1:41, 2 users, load average: 0.00, 0.00, 0.00
[root@bobilinux shell]# ./case.sh
h
f
d
m 使
u
q 退
[h help]:q
[root@bobilinux shell]#

脚本优化

1、脚本中有重复出现的部分,可以把该部分定义成一个函数,重复出现的部

分作为函数体,每次需要应用重复的部分时,直接调用该函数

2、不希望每次操作时都要运行该脚本,希望操作一次后可以继续一直操作,

想退出的时候再退出,这个时候,需要借助 while true 死循环,但是要确

保死循环有结束的条件

3、优化执行的命令,清晰的看结果

#!/bin/bash
#打印菜单
menu(){
cat <<-END
h
f
d
m 使
u
q 退
END
}
menu
while true
do
read -p "请输入你的操作[h help]:" var1
case $var1 in
h)
menu
;;
f)
read -p "请输入你要查看的设备名字[/dev/sdb]:" var2
case $var2 in
/dev/sda)
fdisk -l /dev/sda
;;
/dev/sdb)
fdisk -l /dev/sdb
;;
esac
;;
d)
df -h
;;
m)
free -m
;;
u)
uptime
;;
q)
exit
;;
esac
done

执行结果

[root@bobilinux shell]# ./case.sh 
h
f
d
m 使
u
q 退
[h help]:h
h
f
d
m 使
u
q 退
[h help]:f
[/dev/sdb]:/dev/sda

Disk /dev/sda: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00089914

Device Boot Start End Blocks Id System
/dev/sda1 * 1 26 204800 83 Linux
Partition 1 does not end on cylinder boundary.
/dev/sda2 26 154 1024000 82 Linux swap / Solaris
Partition 2 does not end on cylinder boundary.
/dev/sda3 154 1306 9255936 83 Linux
[h help]:d
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 8.7G 1.8G 6.5G 22% /
tmpfs 931M 0 931M 0% /dev/shm
/dev/sda1 194M 34M 151M 19% /boot
[h help]:m
total used free shared buffers cached
Mem: 1861 173 1688 0 46 36
-/+ buffers/cache: 90 1771
Swap: 999 0 999
[h help]:u
12:29:41 up 1:53, 2 users, load average: 0.00, 0.00, 0.00
[h help]:q
[root@bobilinux shell]#

练习1

模拟2人第一次相亲的场景,使用read让用户输入它的名字,性别,年龄(年

龄放在性别判断后)


1


2
18
yes;
no




18
318



#!/bin/bash
read -p "输入你的姓名:" name
read -p "输入你的性别:" gender

case "$gender" in
|man|male|boy )
read -p "输入你的年龄:" age
if [ $age -ge 18 ];then
read -p "$name先生,你结婚了吗?" anwser
case "$anwser" in
||yes )
echo "结了你还来干嘛?"
;;
|||no )
read -p "有房有车吗?" anwser2
case "$anwser2" in
)
echo "咱就直接去民政局领证吧"
;;
)
echo "不好意思,我去下洗手间"
;;
* )
echo "别浪费时间,请正面回答"
esac
;;
* )
echo "你到底结没结?"
esac

else
echo "$name小子"
fi
;;
|woman|female|girl|lady )
read -p "输入你的年龄:" age
if [ $age -ge 18 ];then
echo "$name女士"
else
echo "$name小姐"
fi
;;
* )
echo "你是泰国来的吗?"
esac

函数

shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数。给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能。

函数的定义

()
{

}



function ()
{

}

函数的调用

当前命令行调用

只在当前命令行有效,退出重新登录或复制会话后的命令行都无法调用

1 shell 
[root@MissHou shell04]# cat fun1.sh
#!/bin/bash
hello(){
echo "hello lilei $1"
hostname
}
menu(){
cat <<EOF
1. mysql
2. web
3. app
4. exit
EOF
}

2source shell.sh使
[root@MissHou shell04]# source fun1.sh

3
[root@bobilinux shell]# menu
1. mysql
2. web
3. app
4. exit


退
[root@bobilinux shell]# exit
logout

Connection closed.

Disconnected from remote host(CentOS 6.5) at 15:24:45.

Type `help' to learn how to use Xshell prompt.
[C:\~]$
[C:\~]$
[C:\~]$
[C:\~]$

Connecting to 192.168.192.131:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.

WARNING! The remote SSH server rejected X11 forwarding request.
Last login: Sun May 8 15:22:57 2022 from 192.168.192.1
[root@bobilinux ~]#
[root@bobilinux ~]#
[root@bobilinux ~]# menu
-bash: menu: command not found



[root@bobilinux shell]# menu
-bash: menu: command not found

定义到全局的/etc/bashrc文件中或用户的~/.bashrc文件中

将函数写到 /etc/bashrc 或 ~/.bashrc 文件中,通过 source /etc/bashrc  使

其生效后,该函数将永久生效(无论是重新登陆后还是复制会话后的命令行)

[root@bobilinux ~]# tail -10 /etc/bashrc 


menu(){
cat <<EOF
1. mysql
2. web
3. app
4. exit
EOF
}
[root@bobilinux ~]# source /etc/bashrc
[root@bobilinux ~]# menu
1. mysql
2. web
3. app
4. exit


退
[root@bobilinux ~]# exit
logout

Connection closed.

Disconnected from remote host(CentOS 6.5) at 15:32:58.

Type `help' to learn how to use Xshell prompt.
[C:\~]$

Connecting to 192.168.192.131:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.

WARNING! The remote SSH server rejected X11 forwarding request.
Last login: Sun May 8 15:32:02 2022 from 192.168.192.1
[root@bobilinux ~]#
[root@bobilinux ~]# menu
1. mysql
2. web
3. app
4. exit



[root@bobilinux ~]# menu
1. mysql
2. web
3. app
4. exit



bash

脚本中调用

该函数只在当前脚本中有效,无法在终端调用

[root@bobilinux shell]# cat case.sh 
#!/bin/bash
#打印菜单
menu(){
cat <<-END
h
f
d
m 使
u
q 退
END
}
menu //


[root@bobilinux shell]# ./case.sh
h
f
d
m 使
u
q 退
[root@bobilinux shell]# menu
-bash: menu: command not found

脚本中调用优化

我们可以把函数都写在一个函数文件里面,在shell脚本中需要调用这个函数的

时候,不需要重新在定义一遍,在脚本里面通过 source 全路径函数文件 后,

就可以直接在脚本中调用函数而不需要重新定义了

[root@bobilinux ~]# cd /tmp/shell/
[root@bobilinux shell]# cat fun1.sh
#!/bin/bash
hello(){
echo "hello world"
hostname
}
menu(){
cat <<EOF
1. mysql
2. web
3. app
4. exit
EOF
}


[root@bobilinux shell]# cat case.sh
#!/bin/bash
source /tmp/shell/fun1.sh
#调用函数文件中的函数
hello
menu
[root@bobilinux shell]# ./case.sh
hello world
bobilinux
1. mysql
2. web
3. app
4. exit

函数中return

1、return可以结束一个函数,类似于前面讲的循环控制语句break

[root@bobilinux shell]# cat fun1.sh 
#!/bin/bash
hello(){
echo "hello world"
return
hostname
}
[root@bobilinux shell]# source fun1.sh
[root@bobilinux shell]# hello
hello world

2、return默认返回函数中最后一个命令的退出状态(用于判定最后一个命令是否正确执行),也可以给定参数值,该参数值的范围是0-256之间

[root@bobilinux shell]# cat fun1.sh 
#!/bin/bash
hello(){
echo "hello world"
hostname
return
}
[root@bobilinux shell]# source fun1.sh
[root@bobilinux shell]# hello
hello world
bobilinux
[root@bobilinux shell]# echo $? #return无参数,$?默认是最后一个命令hostname的执行状态
0


[root@bobilinux shell]# cat fun1.sh
#!/bin/bash
hello(){
echo "hello world"
hostname
return 2
}
[root@bobilinux shell]# source fun1.sh
[root@bobilinux shell]# hello
hello world
bobilinux
[root@bobilinux shell]# echo $? #return有参数,$?就是该参数
2


[root@bobilinux shell]# cat fun1.sh
#!/bin/bash
hello(){
echo "hello world"
hostname
return 2
if [ $? -eq 2 ];then
echo hahaha
fi
}
[root@bobilinux shell]# source fun1.sh
[root@bobilinux shell]# hello
hello world
bobilinux
[root@bobilinux shell]# echo $?
2


[root@bobilinux shell]# cat fun1.sh
#!/bin/bash
hello(){
echo "hello world"
hostname
return 2
}
hello
if [ $? -eq 2 ];then
echo hahahaha
fi
[root@bobilinux shell]# chmod +x fun1.sh
[root@bobilinux shell]# bash -x ./fun1.sh
+ hello
+ echo 'hello world'
hello world
+ hostname
bobilinux
+ return 2
+ '[' 2 -eq 2 ']'
+ echo hahahaha
hahahaha
[root@bobilinux shell]# ./fun1.sh
hello world
bobilinux
hahahaha

3、如果没有return命令,函数将返回最后一个命令的退出状态

[root@bobilinux shell]# cat fun1.sh 
#!/bin/bash
hello(){
echo "hello world"
hostname
}
[root@bobilinux shell]# source fun1.sh
[root@bobilinux shell]# hello
hello world
bobilinux
[root@bobilinux shell]# echo $?
0


[root@bobilinux shell]# cat fun1.sh
#!/bin/bash
hello(){
echo "hello world"
hostnamee
}
[root@bobilinux shell]# source fun1.sh
[root@bobilinux shell]# hello
hello world
-bash: hostnamee: command not found
[root@bobilinux shell]# echo $?
127

应用案例1

需求:写一个脚本让用户输入基本信息(姓名,性别,年龄),如不输入一直提示输入,最后根据用户的信息输出相对应的内容

思路:

      (便)
case

脚本:

#!/bin/bash
#该函数实现用户如果不输入内容则一直循环直到用户输入为止,并且将用户输入的内容打印出来
input_fun()
{
input_var=""
output_var=$1 #调用该函数时,后面接的第一个参数(如 input_fun 请输入你的姓名:)
while [ -z $input_var ]
do
read -p "$output_var" input_var
done
echo $input_var
}




#!/bin/bash
fun(){
read -p "$1" name
if [ -z $name ];then
fun $1
else
echo $name
fi
}


#调用函数并且获取用户的姓名、性别、年龄分别赋值给name、sex、age变量
name=$(input_fun :)
sex=$(input_fun :)
age=$(input_fun :)


#根据用户输入的性别进行匹配判断
case $sex in
man)
if [ $age -gt 18 -a $age -le 35 ];then
echo "中年大叔你油腻了吗?加油"
elif [ $age -gt 35 ];then
echo "保温杯里泡枸杞"
else
echo "年轻有为。。。"
fi
;;
woman)
xxx
;;
*)
xxx
;;
esac

调用函数的时候可以传参数,这个参数在函数内部可以用 $1  $2 替代

应用案例2

需求:实现Nginx 服务自启动

思路:

/etc/init.d/ Nginx  nginxd

cd /etc/init.d/
vim nginxd

脚本:

#!/bin/bash
nginx=/usr/local/nginx/sbin/nginx
start(){
echo "nginx starting .... [OK] "
$nginx
}
start

脚本执行:

shell编程之case语句+函数+正则_正则表达式

脚本优化:

#!/bin/bash
nginx=/usr/local/nginx/sbin/nginx
start(){
echo "nginx starting .... [OK] "
$nginx
}
status(){
if `ss -antpl | grep nginx > /dev/null`
then echo "nginx starting .... "
else echo "nginx stoping .... "
fi
}
stop(){
echo "nginx stoping .... [OK] "
$nginx -s stop
}
case $1 in
start)
start
;;
stop)
stop
;;
restart
stop
start
;;
*)
echo "Usage :$0 {start|stop|restart}"
esac

脚本执行:

shell编程之case语句+函数+正则_正则表达式_02

接下来,让它永久启动

打开我们编写好的nginxd脚本,添加下面两行

# chkconfig: - 84 18
# description: nginx script

shell编程之case语句+函数+正则_case_03

加入chkconfig list

chkconfig --add nginxd

shell编程之case语句+函数+正则_正则表达式_04

默认都是关闭的 off

我们将 5 级别打开 on

chkconfig --list nginxd on

shell编程之case语句+函数+正则_函数_05

接下来,重启操作系统

reboot

shell编程之case语句+函数+正则_正则表达式_06

可以看到, nginx 已经自启动了

综合案例

任务/背景

现有的跳板机虽然实现了统一入口来访问生产服务器,yunwei用户权限太大可

以操作跳板机上的所有目录文件,存在数据被误删的安全隐患,所以希望你做

一些安全策略来保证跳板机的正常使用。

具体要求

1、只允许yunwei用户通过跳板机远程连接后台的应用服务器做一些维护操作

2、公司运维人员远程通过yunwei用户连接跳板机时,跳出以下菜单供选择:

使Jumper-server
1. DB1-Master(centos8)
2. DB2-Slave(centos6)
3. Web1
4. Web2
h. help
q. exit

3、当用户选择相应主机后,直接免密码登录成功

4、如果用户不输入一直提示用户输入,直到用户选择退出

分析

1>  echo   cat
2 case....esac
3
4==>case...esac
5
6>
7>yunwei( ~/.bashrc )

脚本

在此之前,要确保跳板机可以实现免密登录

#!/bin/bash
# jumper-server
# 定义菜单打印功能的函数
menu1()
{
cat <<-EOF
使Jumper-server
1. DB1-Master(centos8)
2. DB2-Slave(centos6)
3. Web(centos8)
h. help
q. exit
EOF
}

menu2()
{
cat <<-EOF
使web-server
1.
2. apache
3. apache
h. help
q. 退
EOF
}

# 调用函数来打印菜单
menu1

while true
do
# 菜单选择,case...esac语句
read -p "请选择你要访问的主机(h help):" host
case $host in
1)
ssh root@192.168.192.130
;;
2)
ssh root@192.168.192.131
;;
3)
clear
menu2
read -p "请输入你要操作的内容(h help):" action
case $action in
1)
ssh root@192.168.192.130 echo "日志正在清理中..."
;;
2)
ssh root@192.168.192.130 echo "apache is running..."
;;
3)
ssh root@192.168.192.130 service apache restart
;;
h)
menu2
;;
q)
echo ""
;;
esac
menu1
;;
h)
clear
menu1
;;
q)
exit
;;
esac
done

脚本位置

1、脚本放在 yunwei 用户的家目录下(在家目录下操作不用 sudo)

2、为了让yunwei用户一登录就进入到菜单里面(限制权限,yunwei用户只能

做菜单中规定的事情),需要把执行该脚本的命令放到 ~/.bashrc 文件里面

(用户一登录就会读取这个文件里面的内容)

[yunwei@bobi ~]$ tail -2 .bashrc 
bash jumper-server.sh
exit #用户一从菜单里退出,就会断开链接,重新登录后又会进入到菜单中

实例:

[root@bobi ~]# su - yunwei
Last login: Sun May 8 19:23:59 CST 2022 on pts/1
使Jumper-server
1. DB1-Master(centos8)
2. DB2-Slave(centos6)
3. Web(centos8)
h. help
q. exit
访:2
Last login: Sun May 8 19:24:04 2022 from 192.168.192.145
[root@bobilinux ~]# exit
logout
Connection to 192.168.192.131 closed.
访:
访:q
[root@bobi ~]#
[root@bobi ~]# su - yunwei
Last login: Sun May 8 19:26:08 CST 2022 on pts/1
使Jumper-server
1. DB1-Master(centos8)
2. DB2-Slave(centos6)
3. Web(centos8)
h. help
q. exit
访:

但是还有个问题

用户直接 CTRL + C 退出当前菜单,这时候发现也能退到 yunwei 用户

访:^C[yunwei@bobi ~]$ 
[yunwei@bobi ~]$
[yunwei@bobi ~]$

怎么办?

脚本优化

需要在脚本中通过 trap 命令来屏蔽这个 CTRL+C 的信号(在脚本首部添加)

# 捕捉到 1 2 3 19 的信号什么都不做
trap '' 1 2 3 19

补充:

1) SIGHUP         
2) SIGINT ^C
3) SIGQUIT 退
9) SIGKILL
15) SIGTERM
18) SIGCONT
19) SIGSTOP
20) SIGTSTP ^Z

正则表达式

什么是正则表达式

正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。许多程序设计语言都支持利用正则表达式进行字符串操作。例如,在Perl中就内建了一个功能强大的正则表达式引擎。正则表达式这个概念最初是由Unix中的工具软件(例如sed和grep)普及开的。

支持正则表达式的程序如:locate |find| vim| grep| sed |awk

专有名词

元字符:在正则中,具有特殊意义的专用字符  . *

前导字符:元字符前面的字符叫前导字符

基础的正则表达式

正常匹配正则表达式

1.     
2* 0
3.*
4^
5$
6^$


7[] [abc]
8[^] [^abc]

9^[] ^[abc]
10^[^] ^[^abc]


11\<
12\>
13\<\> \<hello\> grep -w 'hello'


14\{n\} n go\{2\} google gooogle
15\{n,\} n
16\{n,m\} nm


(17) \(strings\)

Perl内置正则

正则表达式前加 -P

\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

扩展类的正则表达式

需要使用 grep -E (egrep )或 sed -r 进行匹配

+        
?

a|b ab
() hello myself yourself (my|your)self

{n} n \{n\}
{n,} n \{n,\}
{n,m} nm \{n,m\}


# egrep "root|ftp|adm" /etc/passwd
# grep -E "root|ftp|adm" /etc/passwd

# grep -E 'o+gle' test.txt
# grep -E 'o?gle' test.txt

# egrep 'go{2,}' 1.txt
# egrep '(my|your)self' 1.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