第四章:流程控制之条件判断
条件判断语句是一种最简单的流程控制语句。该语句使得程序根据不同的条件来执行不同的程序分支。本节将介绍Shell程序设计中的简单的条件判断语句。
[root@localhost day03]# echo ${2:=100}
-bash: $2: cannot assign in this way
4.1 if条件语句的语法
1、单分支结构
第一种语法:
if <条件表达式>
then指令
fi
第二种语法:
if <条件表达式>;then指令
fi
if id username;thenecho ""
fi
2、双分支结构
if <条件表达式>;then指令序列1
else指令序列2
fi
if id username;thenecho ""
elseecho " cunzai"
fi
3、多分支结构
语法:
if 条件表达式1;then命令序列1
elif 条件表达式2;then命令序列2
....
else命令序列n
fi
4.2 if条件语句案例
##查看内存使用情况:
[root@localhost day04]# free -mtotal used free shared buff/cache available
Mem: 1731 1231 121 15 544 499
Swap: 2047 11 2036
Mem是物理内存,Swap是虚拟内存
[root@localhost day04]# free -m | grep 'Mem'
Mem: 1731 1234 118 15 544 496
[root@localhost day04]# free -m | grep 'Mem' | tr -s " "
Mem: 1731 1234 118 15 544 496
[root@localhost day04]# free -m | grep 'Mem' | tr -s " " | cut -d " " -f 4
118
1、单分支结构
示例1:编写脚本,判断当前系统剩余内存大小,如果低于100M,邮件报警管理员,使用计划任务,每10分钟检查一次。
分析:核心是如何获取当前剩余内存大小
[root@localhost day04]# vim 1.sh
c_mem=`free -m | grep 'Mem' | tr -s " " | cut -d " " -f 4`
#[ $c_mem -lt 100 ] && echo "内存严重不足,小于100,现在是$c_mem" | mail -s "内存报警" 3260385400@qq.com # 需要安装邮箱服务器
#[ $c_mem -lt 200 ] && echo "内存严重不足,小于200,现在是$c_mem"
if [ $c_mem -lt 200 ];thenecho "内存严重不足,小于200,现在是$c_mem"
fi
[root@localhost day04]# bash 1.sh
内存严重不足,小于200,现在是114
示例2:编写脚本,判断当前脚本执行者,如果不是root用户,提示用户脚本需要root用户来执行,并退出。
分析:核心在于判断当前脚本执行者
方法1:whomai
[root@localhost ~]# whoami
root
方法2:id -u,结构为零则为root
[root@localhost ~]# id -u
0
方法3:使用环境变量
[root@localhost ~]# echo $USER
root
[student@localhost ~]$ echo $UID
1000###### 脚本 ######
[root@localhost day04]# vim 2.sh
c_user=`whoami`
if [ !$c_user == root ];thenecho "执行脚本通过root进行处理"exit 100
elseecho "不是root用户,请切换至root用户执行该脚本"fi
[root@localhost day04]# bash 2.sh
不是root用户,请切换至root用户执行该脚本
[zhou@localhost day04]$ bash 2.sh
不是root用户,请切换至root用户执行该脚本
2、双分支结构
例1:判断数字大于500则执行big.sh 小于等于500则退出脚本,并输出报错信息
read -p "s数字" num
if [ $num -gt 500 ] ;thenbash /big.sh
elseexit 0
fi### 执行脚本时,需要判断当前文件是否存在执行权限,若没有,需要添加文件的执行权限。
[root@localhost day04]# ll
total 16
-rw-r--r--. 1 root root 645 Nov 16 15:17 1.sh
-rw-r--r--. 1 root root 704 Nov 16 15:03 1.txt
-rw-r--r--. 1 root root 488 Nov 16 15:28 2.sh
-rw-r--r--. 1 root root 1399 Nov 16 14:51 lianxi.sh
[root@localhost day04]# chmod u+x 1.sh # 给1.sh文件添加执行权限
[root@localhost day04]# ll
total 16
-rwxr--r--. 1 root root 645 Nov 16 15:17 1.sh
-rw-r--r--. 1 root root 704 Nov 16 15:03 1.txt
-rw-r--r--. 1 root root 488 Nov 16 15:28 2.sh
-rw-r--r--. 1 root root 1399 Nov 16 14:51 lianxi.sh
[root@localhost day04]# [ -x 1.sh ] && echo "有权限" || echo "没有权限"
有权限
[root@localhost day04]# su zhou
[zhou@localhost day04]$ [ -x 1.sh ] && echo "有权限" || echo "没有权限"
没有权限
例 2:判断 sshd 进程是否运行,如果服务未启动则启动相应服务。
ps -aux systemctl is-active/status netstat lsof
#####分析:核心在于判断进程是否运行的方法?
# 方法1:查看进程 systemctl is-active sshd systemctl status sshd
[root@localhost ~]# ps -elf | grep sshd | grep -v grep | wc -l
4
# 方法2:查看端口
# 本地查看netstat、ss、lsof -------https://www.jianshu.com/p/644e75af4405
# 远程查看telnet、nmap、nc
[root@localhost ~]# netstat -lnupt | grep 22 | wc -l
2
[root@localhost ~]# ss -lnupt | grep 22 | wc -l
2
[root@localhost ~]# lsof -i:22
[root@localhost ~]# nmap -p 22 127.0.0.1 | grep open | wc -l
1##### 脚本编程 ######
[root@localhost day04]# vim 3.sh
#!/bin/bash
read -p "请输入要判断的服务程序名称:" service
value=`systemctl is-active $service`
if [ $value == 'active' ];thenecho "$service服务正在运行"
elseecho "$service未运行,请重启该服务"fi
[root@localhost day04]# bash 3.sh
请输入要判断的服务程序名称:sshd
sshd服务正在运行
[root@localhost day04]# bash 3.sh
请输入要判断的服务程序名称:nginx # 在这里的nginx服务是没有启动的
nginx未运行,请重启该服务
扩展远程端口监听
telnet nmap nc
- nc:netcat 是一个简单的 Unix 工具,它使用 TCP 或 UDP 协议去读写网络连接间的数据。
nmap
:(“Network Mapper”)是一个用于网络探索和安全审计的开源工具,被设计用来快速地扫描大规模网络。telnet
:被用来交互地通过 TELNET 协议与另一台主机通信。
1)nc
即 netcat
。netcat
是一个简单的 Unix 工具,它使用 TCP 或 UDP 协议去读写网络连接间的数据。
它被设计成为一个可信赖的后端工具,可被直接使用或者简单地被其他程序或脚本调用。
与此同时,它也是一个富含功能的网络调试和探索工具,因为它可以创建你所需的几乎所有类型的连接,并且还拥有几个内置的有趣功能。
netcat
有三类功能模式,它们分别为连接模式、监听模式和隧道模式。
nc
(netcat
)命令的一般语法:
$ nc [-options] [HostName or IP] [PortNumber]
在下面的例子中,我们将检查远程 Linux 系统中的 22 端口是否开启。
假如端口是开启的,你将获得类似下面的输出。
[root@localhost day04]# nc -zvw3 192.168.235.128 22
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Connected to 192.168.235.128:22.
Ncat: 0 bytes sent, 0 bytes received in 0.02 seconds.
[root@localhost day04]# nc -zvw3 192.168.235.128 80
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Connection refused.
命令详解:
nc
:即执行的命令主体;z
:零 I/O 模式(被用来扫描);v
:显式地输出;w3
:设置超时时间为 3 秒;192.168.1.8
:目标系统的 IP 地址;22
:需要验证的端口。
当检测到端口没有开启,你将获得如下输出:
# nc -zvw3 192.168.1.95 22
nc: connect to 192.168.1.95 port 22 (tcp) failed: Connection refused
**2)nmap
(“Network Mapper”)**是一个用于网络探索和安全审计的开源工具,被设计用来快速地扫描大规模网络,尽管对于单个主机它也同样能够正常工作。
nmap
以一种新颖的方式,使用裸 IP 包来决定网络中的主机是否可达,这些主机正提供什么服务(应用名和版本号),它们运行的操作系统(系统的版本),它们正在使用的是什么包过滤软件或者防火墙,以及其他额外的特性。
尽管 nmap
通常被用于安全审计,许多系统和网络管理员发现在一些日常任务(例如罗列网络资产、管理服务升级的计划、监视主机或者服务是否正常运行)中,它也同样十分有用。
nmap
的一般语法:
$ nmap [-options] [HostName or IP] [-p] [PortNumber]
安装nmap:
[root@localhost day04]# mount /dev/sr1 /mnt
mount: /mnt: WARNING: source write-protected, mounted read-only.
[root@localhost day04]# dnf install nmap -y
查看安装nmap服务需要安装的安装包:
[root@localhost day04]# dnf whatprovides nmap
Updating Subscription Management repositories.
Unable to read consumer identityThis system is not registered with an entitlement server. You can use subscription-manager to register.Last metadata expiration check: 0:01:50 ago on Sat 16 Nov 2024 04:12:04 PM CST.
nmap-3:7.92-1.el9.x86_64 : Network exploration tool and security scanner
Repo : @System
Matched from:
Provide : nmap = 3:7.92-1.el9nmap-3:7.92-1.el9.x86_64 : Network exploration tool and security scanner
Repo : AppStream
Matched from:
Provide : nmap = 3:7.92-1.el9
假如端口是开启的,你将获得如下的输出:
[root@localhost day04]# nmap 192.168.235.131 -p 22
Starting Nmap 7.92 ( https://nmap.org ) at 2024-11-16 16:18 CST
Nmap scan report for 192.168.235.131
Host is up (0.00034s latency).PORT STATE SERVICE
22/tcp open ssh
MAC Address: 00:0C:29:C3:99:AC (VMware)Nmap done: 1 IP address (1 host up) scanned in 0.27 seconds
假如端口没有开启,你将得到类似下面的结果:
# nmap 192.168.1.8 -p 80
Starting Nmap 7.70 ( https://nmap.org ) at 2019-03-16 04:30 IST
Nmap scan report for 192.168.1.8
Host is up (0.00036s latency).PORT STATE SERVICE
80/tcp closed httpNmap done: 1 IP address (1 host up) scanned in 13.07 seconds
3)telnet
命令被用来交互地通过 TELNET 协议与另一台主机通信。
telnet
命令的一般语法:
$ telnet [HostName or IP] 80
假如探测成功,你将看到类似下面的输出:
[root@localhost day04]# telnet 192.168.235.131 22
Trying 192.168.235.131...
Connected to 192.168.235.131.
Escape character is '^]'.
SSH-2.0-OpenSSH_8.7Invalid SSH identification string.
Connection closed by foreign host.
假如探测失败,你将看到类似下面的输出:
[root@localhost day04]# telnet 192.168.235.131 80
Trying 192.168.235.131...
telnet: connect to address 192.168.235.131: No route to host
示例 2:检查主机是否存活,并输出结果
分析:最简单方式是通过ping命令检测ping -c 2 -W 1 192.168.95.16 &> /dev/null通过$?判断,也可以直接 if ping -c 2 -W 1 192.168.95.16 &> /dev/null测试
3、多分支结构
示例1:两个整数比较大小。
示例2:根据用户输入成绩,判断优良中差。
85-100 优秀–A 70-84 良好–B 60-79 合格–C 60分以下不合格–D
#### if 结构 ####
[root@localhost day04]# vim 4.sh
read -p "请输入你的成绩:" score
if [ $score -ge 85 -a $score -le 100 ];thenecho "你的成绩为$score,优秀-----A"
elif [[ $score -ge 70 && $score -le 84 ]];thenecho "你的成绩为$score,良好-----B"
elif `test $score -ge 60 -a $score -le 69`;thenecho "你的成绩为$score,合格-----C"
elseecho "你的成绩为$score,不合格-----D"
fi
[root@localhost day04]# bash 4.sh
请输入你的成绩:95
你的成绩为95,优秀-----A
[root@localhost day04]# bash 4.sh
请输入你的成绩:55
你的成绩为55,不合格-----D
##### case 结构 ####
[root@localhost day04]# vim 5.sh
read -p "请输入你的成绩:" score
case $score in8[5-9]|9[0-9]|100) echo "你的成绩为$score,优秀-----A";;7[0-9]|8[0-4]) echo "你的成绩为$score,良好-----B";;6[0-9]) echo "你的成绩为$score,合格-----C";;*) echo "你的成绩为$score,不合格-----D";;
esac
[root@localhost day04]# vim 5.sh
read -p "请输入你的成绩:" score
if [[ $score =~ ^[0-9]*$ ]];thenif [ $score -ge 0 -a $score -le 100 ];thenif [ $score -ge 85 -a $score -le 100 ];thenecho "你的成绩为$score,优秀-----A"elif [[ $score -ge 70 && $score -le 84 ]];thenecho "你的成绩为$score,良好-----B"elif `test $score -ge 60 -a $score -le 69`;thenecho "你的成绩为$score,合格-----C"elseecho "你的成绩为$score,不合格-----D"fielseecho "请输入1-100之间的正确成绩."fi
elseecho "输入的不是正确的成绩,请输入1-100正确的成绩"
fi
[root@localhost day04]# bash 5.sh
请输入你的成绩:55
你的成绩为55,不合格-----D
[root@localhost day04]# bash 5.sh
请输入你的成绩:110
请输入1-100之间的正确成绩.
示例3:根据用户输入,判断是数字、字母或其他字符。
read -p "Please enter a character, press enter to continue: " str
if echo "$str"|grep "[a-zA-Z]" >/dev/null
thenecho "Input is letter"
elif echo "$str"|grep "[0-9]" >/dev/null
thenecho "Input is number"
elseecho "Input is other"
fi
示例4:判断当前主机的CPU生产商,其信息在/proc/cpuinfo文件中vendor_id一行中。 如果其生产商为GenuineIntel,就显示其为Intel公司; 如果其生产商为AuthenticAMD,就显示其为AMD公司; 否则,就显示无法识别;
Vendor=$(grep "vendor_id" /proc/cpuinfo |uniq| awk -F: '{print $NF}')if [[ $Vendor =~ [[:space:]]*GenuineIntel$ ]];thenecho "intel"
elif [[ $Vendor =~ [[:space:]]*AuthenticAMD$ ]];thenecho "AMD"
elseecho "Unknown"
fi
案例5: if嵌套#1.两个整数比较大小
read -p "请输入整数" a
read -p "在次输入" b
if [ -n "$a" -a -n "$b" ];then[[ "$a" =~ ^[0-9]+$ ]] && [[ "$b" =~ ^[0-9]+$ ]]# echo "$a"|[ -n "`sed -n '/^[0-9]*$/p'`" ] && echo "$b" |[-n "`sed -n '/^[0-9]*$/p'`"]if [ $? -eq 0 ];thenif [[ "$a" -gt "$b" ]];thenecho 第一个数大于第二个数elif [[ "$a" -lt "$b" ]];thenecho 第一个数小于第二个数elseecho 两个数相等fielseecho 请输入数字fi
elseecho 输入信息不能为空
fi
4.3 exit退出程序 exit
exit语句的基本作用是终止Shell程序的执行。除此之外,exit语句还可以带一个可选的参数,用来指定程序退出时的状态码。exit语句的基本语法如下: exit status 其中,status参数表示退出状态,该参数是一个整数值,其取值范围为0~255。与其他的Shell命令的一样,Shell程序的退出状态也储存在系统变量$?中,因此,用户可以通过该变量取得Shell程序返回给父进程的退出状态码。
4.4 多条件判断语句case
case可针对谋变量不同的值结果进行情景分析。
case语句语法:
case 变量名 in 值1) 指令1 ;; 值2) 指令2 ;; 值3) 指令3 ;; *)默认
esac
示例1:由用户从键盘输入一个字符,并判断该字符是否为字母、数字或者其他字符, 并输出相应的提示信
read -p "Please enter a character, press enter to continue: " -n 1 str
if echo "$str"|grep "[a-zA-Z]" >/dev/null
thenecho "Input is letter"
elif echo "$str"|grep "[0-9]" >/dev/null
thenecho "Input is number"
elseecho "Input is other"
firead -p "Please enter a character, press enter to continue: " -n 1 KEY
case "$KEY" in[[:alpha:]])echo "Input is letter";;[0-9])echo "Input is number";;*)echo "Input is other characters"
esac
示例2:将判断分数范围多分支语句用case语句实现
read -p "Please enter your score (0-100): " grade
case "$grade" in8[5-9]|9[0-9]|100) {85..100} [85-100]echo "$grade, A";;7[0-9]|8[0-4])echo "$grade, B";;6[0-9])echo "$grade, C";;*)echo "$grade, D"
esac
示例3:编写菜单选择处理
- 查看/目录下所有文件
- 当前位置创建文本文件file
- 查看/etc/passwd文件内容
练习:
1、ping主机测试
2、判断一个用户是否存在
3、判断当前内核主版本是否为3,且次版本是否大于10
4、判断vsftpd软件包是否安装,如果没有则安装
5、判断httpd是否运行
6、判断指定的主机是否能ping通,必须使用$1变量
7、报警脚本,要求如下:根分区剩余空间小于20%向用户alice发送告警邮件配合crond每5分钟检查一次[root@locaklhost ~]# echo "邮件正文" | mail -s "邮件主题" alice
作业:
通过shell脚本分析部署nginx网络服务
1.接收用户部署的服务名称
2.判断服务是否安装
已安装;自定义网站配置路径为/www;并创建共享目录和网页文件;重启服务
没有安装;安装对应的软件包
3.测试
判断服务是否成功运行;
已运行,访问网站
未运行,提示服务未启动,并显示自定义的配置文件内容
4.以上配置没有问题,请邮件告知我,并将脚本代码(代码文件)邮件发送我
[root@localhost day04]# mount /dev/sr1 /mnt
mount: /mnt: WARNING: source write-protected, mounted read-only.
[root@localhost day04]# dnf install s-nail -y[root@localhost ~]# vim /etc/s-nail.rc
set from=xxxxxxx@163.com -----邮箱账号
set smtp=smtp.163.com
set smtp-auth-user=xxxxxxxx@163.com --------邮箱账号
set smtp-auth-password=xxxxxxx ------邮箱授权码
set smtp-auth=login
# 编辑脚本
[root@localhost ~]# vim nginx.sh
systemctl stop firewalld.service
setenforce 0
# 1,接收用户部署的服务名称
read -p "请输入需要部署的服务名称:" service
#value=`systemctl is-active $service`
#if [ $value = 'active' ];then
if systemctl is-active --quiet $service;thenecho "$service服务部署成功"
elseecho "$service服务未部署,请重新部署该服务"
fi# 2,判断服务是否安装
# 自定义网站配置路径为/www
web="/www"
shard="$web/shared"
file="/etc/nginx/conf.d"
config=$file/test.conf
if command -v $service &> /dev/null;thenecho "$service服务已安装."# 创建配置文件路径mkdir -p $web# 创建共享目录和网页文件mkdir -p $shardtouch $config/test.confecho "欢迎来到$service服务页面" > $web/index.html # 此时可以通过IP访问该网页# 更改配置文件
cat <<EOF > $config
server{listen 80;root $web;location / {index index.html;}
}
EOF# 重启服务systemctl restart $service
elseecho "$service服务未安装,下面将会对$service服务进行安装..."# 挂载mount /dev/sr1 /mnt# 安装服务dnf install $service -y
fi# 3,测试
echo "正在检查$service服务是否成功运行..."
if systemctl is-active --quiet $service;thenecho "$service正在运行."echo "请访问 http://$(hostname -I)/ 查看测试网页."
elseecho "$service未运行!"echo "$service自定义的配置文件内容如下:"cat $config
fi# 运行脚本
[root@localhost ~]# bash nginx.sh