当前位置: 首页 > ds >正文

11.Shell脚本修炼手册---IF 条件语句的知识与实践

if 条件语句的知识与实践

文章目录

    • if 条件语句的知识与实践
      • if 条件语句
        • if 条件语句的语法
          • 1. 单分支结构(满足条件才执行)
          • 2. 双分支结构(二选一执行)
          • 3. 多分支结构(多选一执行)
        • if 条件表达式的 5 种写法
        • 逻辑运算符替换规则(巩固扩展)
          • **一、整数比较运算符(常用)**
          • 二、字符串比较运算符(常用)
          • 三、文件测试运算符(常用)
        • if 条件语句实践
          • **实验 1:检测并启动 sshd 服务**
          • **实验 2:通过参数控制 sshd 服务(start/stop/restart)**
          • **实验 3:三个整数从大到小排序**
          • **实验 4:监控系统内存(低于 100M 时发邮件)**
      • if 条件语句企业案例精讲
        • 监控 Web 服务(Apache)和数据库(MySQL)
        • 比较两个整数的大小(带参数校验)
        • 判断字符串是否为数字(多种方法)
        • 开发 rsync 服务启动脚本(模拟系统服务)

if 条件语句

if 条件语句是 Linux 运维中最常用的语句之一,无论是简单的服务检查还是复杂的业务判断,都离不开它。掌握 if 条件语句,能让你轻松应对各种场景下的逻辑判断需求。

if 条件语句的语法

if 条件语句的核心逻辑和我们日常说的 “如果… 那么…” 完全一致。根据判断场景的复杂程度,它分为三种结构:单分支、双分支和多分支。

1. 单分支结构(满足条件才执行)

单分支就像日常决策中的 “如果满足 A,就做 B”。比如 “如果下雨,就带伞”。

语法格式 1(换行写法):

if <条件表达式>  # 判断条件是否成立then           # 如果成立,就执行下面的指令指令           # 具体要执行的操作
fi              # 结束判断(if的反向拼写,标记语句结束)

语法格式 2(紧凑写法):

if <条件表达式>;then  # 分号替代换行,功能和上面完全一样指令
fi

举个例子:
如果/tmp/bq目录不存在,就创建它。

# 判断/tmp/bq是否不是目录(!表示否定,-d检查是否为目录)
if [ ! -d /tmp/bq ];thenmkdir /tmp/bq  # 不存在则创建目录
fi

嵌套用法:
if 语句内部还可以再放 if 语句(类似 “如果 A 成立,且 B 也成立,就做 C”)。注意每个 if 都要对应一个 fi,缩进对齐更易读。

if [ 条件1 ];then# 条件1成立后,再判断条件2if [ 条件2 ];then指令  # 只有条件1和条件2都成立才执行fi  # 关闭条件2的判断
fi  # 关闭条件1的判断
2. 双分支结构(二选一执行)

双分支对应 “如果满足 A,就做 B;否则,就做 C”。比如 “如果考试及格,就出去玩;否则,在家复习”。

语法格式:

if <条件表达式>;then指令集1  # 条件成立时执行
else指令集2  # 条件不成立时执行
fi

举个例子:
检查/tmp/bq目录是否存在,存在就提示,不存在就创建。

if [ -d /tmp/bq ];thenecho "/tmp/bq 已存在"  # 存在时提示
elsemkdir /tmp/bq          # 不存在时创建
fi
3. 多分支结构(多选一执行)

多分支对应 “如果满足 A,做 B;如果满足 C,做 D;否则,做 E”。比如 “如果成绩≥90,评优;≥60,及格;否则,挂科”。

语法格式:

if <条件表达式1>;then指令1  # 满足条件1时执行
elif <条件表达式2>;then  # else if的缩写,可多个指令2  # 满足条件2时执行
else指令3  # 所有条件都不满足时执行
fi

注意:

  • 每个elif后面必须跟then
  • 最后一个else后面没有then
if 条件表达式的 5 种写法

if 后面的 “条件表达式” 可以有多种形式,本质都是判断 “成立(真)” 或 “不成立(假)”,选一种你习惯的即可。

表达式类型语法示例说明
test 命令if test 1 -eq 1;then echo "相等";fi最基础的条件判断命令
[] 符号if [ 1 -eq 1 ];then echo "相等";fi简化的 test 写法(注意括号内外有空格)
[[]] 符号if [[ 1 -eq 1 ]];then echo "相等";fi增强版 [],支持更多语法(如字符串模式匹配)
(()) 符号if ((1 == 1));then echo "相等";fi专门用于整数计算和比较
直接用命令if ls /tmp;then echo "成功";fi命令执行成功(返回值 0)则条件成立

举个例子:用命令作为条件
检查 sshd 服务是否未运行,如果是则输出 “fail”:

# systemctl status sshd | grep -q inactive:查找"inactive"(静默模式,不输出内容)
# 命令执行成功(找到关键词)则条件成立,执行echo
if systemctl status sshd | grep -q inactive; then echo fail; fi
逻辑运算符替换规则(巩固扩展)

在shell脚本中,逻辑运算符有特定的写法,不能直接用&&(与)、||(或)等符号进行表达,需要有专门的关键字替代,为了增强记忆,如下在进行一个逻辑运算符的详细替换规则和示例操作:

一、整数比较运算符(常用)

用于比较两个整数的大小关系,只能用于数字,不能用于字符串或小数。

运算符含义示例
-eq等于(equal)[ 5 -eq 5 ] → 成立(返回真)
-ne不等于(not equal)[ 5 -ne 3 ] → 成立
-gt大于(greater than)[ 10 -gt 5 ] → 成立
-lt小于(less than)[ 3 -lt 8 ] → 成立
-ge大于等于(greater or equal)[ 7 -ge 7 ] → 成立
-le小于等于(less or equal)[ 4 -le 6 ] → 成立

示例1:基本整数的比较

a=10
b=20# 判断a是否等于b
if [ $a -eq $b ];thenecho "$a 等于 $b"
elseecho "$a 不等于 $b"  # 执行此句(10≠20)
fi# 判断a是否大于b
if [ $a -gt $b ];thenecho "$a 大于 $b"
elseecho "$a 不大于 $b"  # 执行此句(10<20)
fi

示例2:结合逻辑运算符的多条件判断

score=85# 判断分数是否在60~100之间(包含边界)
if [ $score -ge 60 -a $score -le 100 ];thenecho "成绩有效:$score 分"  # 85在范围内,执行此句
elseecho "成绩无效"
fi# 判断分数是否小于60或大于100(无效成绩)
if [ $score -lt 60 -o $score -gt 100 ];thenecho "成绩无效"
elseecho "成绩有效:$score 分"  # 执行此句
fi
二、字符串比较运算符(常用)

用于比较字符串的内容或长度,注意字符串变量最好用双引号包裹,避免空格导致的错误。

运算符含义示例
===字符串相等(==[]中兼容,推荐用=[ "abc" = "abc" ] → 成立
!=字符串不相等[ "abc" != "def" ] → 成立
-z字符串长度为 0(空字符串)[ -z "" ] → 成立
-n字符串长度不为 0(非空字符串)[ -n "hello" ] → 成立
<字符串按字典序小于(需用\转义,或在[[]]中使用)[ "apple" \< "banana" ] → 成立
>字符串按字典序大于(需用\转义)[ "cat" \> "bat" ] → 成立

示例 3:字符串相等性判断

name="Alice"
input="alice"# 判断两个字符串是否完全相等(区分大小写)
if [ "$name" = "$input" ];thenecho "名字匹配"
elseecho "名字不匹配"  # 执行此句(Alice≠alice)
fi# 判断字符串是否为空
empty_str=""
if [ -z "$empty_str" ];thenecho "字符串为空"  # 执行此句
elseecho "字符串非空"
fi

示例 4:字符串字典序比较

str1="apple"
str2="apricot"# 判断str1是否按字典序小于str2(注意<需要转义)
if [ "$str1" \< "$str2" ];thenecho "$str1 在字典中位于 $str2 之前"  # 执行此句(apple < apricot)
elseecho "$str1 在字典中位于 $str2 之后"
fi
三、文件测试运算符(常用)

用于判断文件的类型、权限等属性,是运维脚本中非常常用的判断条件。

运算符含义示例
-f是否为普通文件(非目录、非设备)[ -f "test.txt" ] → 文件存在且是普通文件则成立
-d是否为目录[ -d "docs" ] → 目录存在则成立
-e文件或目录是否存在[ -e "file.txt" ] → 存在则成立
-r是否有读权限[ -r "data.txt" ] → 有读权限则成立
-w是否有写权限[ -w "log.txt" ] → 有写权限则成立
-x是否有执行权限[ -x "script.sh" ] → 有执行权限则成立
-s文件是否存在且不为空(大小 > 0)[ -s "info.txt" ] → 文件非空则成立

示例 5:文件属性判断

file="example.sh"# 判断文件是否存在且是可执行脚本
if [ -f "$file" -a -x "$file" ];thenecho "$file 是可执行脚本,正在运行..."./"$file"  # 执行脚本
elseecho "$file 不存在或不可执行"
fi# 判断目录是否存在,不存在则创建
dir="backup"
if [ ! -d "$dir" ];then  # !否定-d,目录不存在则成立echo "目录 $dir 不存在,创建中..."mkdir "$dir"
elseecho "目录 $dir 已存在"
fi
if 条件语句实践
实验 1:检测并启动 sshd 服务

实验流程:

  1. 检查 sshd 服务状态(用命令返回值判断)
  2. 如果服务未运行,启动服务并提示
  3. 如果服务已运行,直接提示

实现代码:

#!/bin/bash
# 检查sshd服务状态(&>/dev/null:屏蔽输出,只保留返回值)
systemctl is-active sshd &>/dev/null# $?是上一条命令的返回值:0表示成功(服务运行),非0表示失败(服务未运行)
if [ $? -ne 0 ];then  # -ne:不等于(如果返回值非0,说明服务未运行)echo "sshd未运行,正在启动..."systemctl start sshd  # 启动服务
elseecho "sshd已运行"
fi
实验 2:通过参数控制 sshd 服务(start/stop/restart)

实验流程:

  1. 接收用户输入的参数(如 start)
  2. 根据参数执行对应的操作(启动 / 停止 / 重启)
  3. 若参数无效,提示正确用法

实现代码:

#!/bin/bash
# 判断参数是否为start/stop/restart
if [ "$1" = "start" ];thensystemctl start sshd  # 启动服务
elif [ "$1" = "stop" ];thensystemctl stop sshd   # 停止服务
elif [ "$1" = "restart" ];thensystemctl restart sshd  # 重启服务
else# 提示正确用法($0表示脚本自身的文件名)echo "用法:$0 start|stop|restart"exit 1  # 非0退出码表示执行出错
fi
实验 3:三个整数从大到小排序

实验流程:

  1. 定义三个整数变量
  2. 两两比较,通过交换值让变量从大到小排列
  3. 输出排序结果

实现代码:

#!/bin/bash
a=10
b=20
c=30# 第一步:确保a >= b(如果a < b,交换a和b的值)
if [ $a -lt $b ];then  # -lt:小于num=$b    # 临时变量num存b的值b=$a      # b换成a的值a=$num    # a换成原来的b的值(现在a > b)
fi# 第二步:确保b >= c(如果b < c,交换b和c的值)
if [ $b -lt $c ];thennum=$cc=$bb=$num    # 现在b > c
fi# 第三步:再次确保a >= b(经过前两步,可能a < b,需再检查)
if [ $a -lt $b ];thennum=$bb=$aa=$num    # 最终a >= b >= c
fiecho "$a>$b>$c"  # 输出结果:30>20>10
实验 4:监控系统内存(低于 100M 时发邮件)

实验流程:

  1. 获取系统当前空闲内存(单位:MB)
  2. 判断空闲内存是否小于 100M
  3. 若小于,给 root 用户发报警邮件
  4. 设置定时任务,每 3 分钟执行一次

实现代码:

#!/bin/bash
# 获取第2行(NR==2)第4列($4)的空闲内存值(free -m以MB显示内存)
FreeMem=$(free -m | awk 'NR==2 { print $4}')# 如果空闲内存小于100M,发邮件报警
if [ $FreeMem -lt 100 ];then# echo内容作为邮件正文,-s指定主题,发送给root@localhostecho "内存不足!当前空闲内存:${FreeMem}M" | mail -s "内存报警" root@localhost
fi

设置定时任务:

# 给脚本添加执行权限
chmod +x monitor_mem.sh# 编辑定时任务(*/3表示每3分钟)
crontab -e
# 添加以下内容(脚本路径替换为实际路径)
*/3 * * * * /home/bq/monitor_mem.sh

if 条件语句企业案例精讲

监控 Web 服务(Apache)和数据库(MySQL)

实验目标: 检测服务是否正常,若异常则提示(或自动启动)。
实验流程:

  1. 准备 Web(Apache)和数据库(MySQL)环境
  2. 用命令行测试服务是否正常(端口检测 / 进程检测)
  3. 编写监控脚本,用 if 判断服务状态并输出结果

1. 环境准备

# 安装Apache(Web服务,默认端口80)
sudo yum install -y httpd
sudo systemctl enable httpd --now  # 开机启动并立即启动# 安装MySQL(数据库,默认端口3306,CentOS中常用mariadb替代)
sudo yum install -y mariadb-server
sudo systemctl enable mariadb --now# 关闭防火墙(避免端口被拦截)
sudo systemctl disable firewalld --now

2. 命令行测试服务状态

# 检测MySQL端口(3306)是否监听(ss -lnt:列出监听的TCP端口)
ss -lnt | grep ':3306' | wc -l  # 结果为1表示端口正常监听# 检测Apache端口(80)是否监听
ss -lnt | grep ':80' | wc -l    # 结果为1表示正常

3. 编写监控脚本

监控 MySQL 的脚本:

#!/bin/bash
# 用ss命令检测3306端口是否被监听(-q:静默模式,只返回成功/失败)
if ss -lnt | grep -q ':3306';thenecho "MySQL运行正常"
elseecho "MySQL未运行!"# 可选:自动启动服务(取消下面一行注释)# sudo systemctl start mariadb
fi

监控 Apache 的脚本:

#!/bin/bash
# 用curl访问本地80端口(--head:只取响应头,-s:静默模式)
if curl -s --head 127.0.0.1:80 | grep -q "HTTP/1.1 200 OK";thenecho "Apache运行正常"
elseecho "Apache未运行!"# 可选:自动启动服务# sudo systemctl start httpd
fi
比较两个整数的大小(带参数校验)

实验目标: 接收用户输入的两个整数,比较大小并输出结果(需先校验参数是否合法)。
实验流程:

  1. 检查用户输入的参数个数是否为 2
  2. 检查参数是否为整数(非整数则报错)
  3. 比较两个整数的大小并输出结果

实现代码:

#!/bin/bash
# 步骤1:检查参数个数($#表示参数总数,-ne 2:不等于2)
if [ $# -ne 2 ];thenecho "用法:$0 数字1 数字2"  # 提示正确输入方式exit 1  # 退出并返回错误码
fi# 步骤2:赋值($1是第一个参数,$2是第二个参数)
a=$1
b=$2# 步骤3:检查参数是否为整数(expr计算非整数会报错,返回值非0)
expr $a + 1 &>/dev/null  # 用expr检测a是否为整数(+1不影响结果,只测合法性)
RETVAL1=$?  # 保存检测结果(0为整数,非0为非整数)
expr $b + 1 &>/dev/null
RETVAL2=$?# 如果a或b不是整数,提示错误
if [ $RETVAL1 -ne 0 -o $RETVAL2 -ne 0 ];then  # -o:或者echo "请输入两个整数!"exit 2
fi# 步骤4:比较大小并输出
if [ $a -lt $b ];then  # -lt:小于echo "$a < $b"
elif [ $a -eq $b ];then  # -eq:等于echo "$a = $b"
elseecho "$a > $b"
fi
判断字符串是否为数字(多种方法)

方法 1:删除所有数字后检查是否为空
原理:如果字符串全是数字,删除数字后会变成空字符串。

# 示例:判断变量string是否为数字
string=1234
# ${string//[0-9]/}:删除string中所有0-9的数字
if [ -z "${string//[0-9]/}" ];then  # -z:检查字符串是否为空echo "是数字"
elseecho "不是数字"
fi

方法 2:用正则表达式匹配
原理:^[0-9]+$表示 “从开头到结尾全是数字”。

string=1234
# [[ ]]支持=~正则匹配
if [[ $string =~ ^[0-9]+$ ]];thenecho "是数字"
elseecho "不是数字"
fi
开发 rsync 服务启动脚本(模拟系统服务)

实验目标: 实现类似系统服务的启动脚本(支持 start/stop/restart/status)。
实验流程:

  1. 安装 rsync 服务并测试启动 / 停止命令
  2. 编写脚本,通过参数判断执行对应操作
  3. 验证脚本功能(启动 / 停止 / 重启 / 查看状态)

1. 环境准备

# 安装rsync(数据同步工具,默认端口873)
sudo yum install -y rsync# 启动rsync服务(--daemon:以守护进程模式运行)
sudo rsync --daemon# 检查端口是否启动(873为rsync默认端口)
ss -lnt | grep ':873'  # 有输出表示启动成功# 停止rsync服务(pkill:杀死进程)
sudo pkill rsync

2. 编写启动脚本

#!/bin/bash
# rsync服务控制脚本(支持start/stop/restart/status)# 步骤1:检查参数个数(必须传入1个参数)
if [ $# -ne 1 ];thenecho "用法:$0 [ start | stop | restart | status ]"exit 1
fi# 步骤2:根据参数执行操作
if [ "$1" = "start" ];then# 启动服务sudo rsync --daemonsleep 2  # 等待2秒,确保服务启动完成# 检查是否启动成功(检测873端口)if ss -lnt | grep -q ':873';thenecho "rsync已启动"elseecho "rsync启动失败"fielif [ "$1" = "stop" ];then# 停止服务sudo pkill rsync &>/dev/nullsleep 2# 检查是否停止成功if ! ss -lnt | grep -q ':873';then  # !表示否定echo "rsync已停止"elseecho "rsync停止失败"fielif [ "$1" = "status" ];then# 查看状态if ss -lnt | grep -q ':873';thenecho "rsync正在运行"elseecho "rsync未运行"fielif [ "$1" = "restart" ];then# 重启服务(先停止,再启动)sudo pkill rsync &>/dev/nullsleep 1sudo rsync --daemonsleep 1# 检查重启结果if ss -lnt | grep -q ':873';thenecho "rsync已重启"elseecho "rsync重启失败"fielse# 无效参数echo "用法:$0 [ start | stop | restart | status ]"exit 1
fi

3. 验证脚本

# 给脚本添加执行权限
sudo chmod +x /etc/init.d/rsyncd# 测试启动
sudo /etc/init.d/rsyncd start  # 输出:rsync已启动# 测试查看状态
sudo /etc/init.d/rsyncd status  # 输出:rsync正在运行# 测试停止
sudo /etc/init.d/rsyncd stop   # 输出:rsync已停止# 测试重启
sudo /etc/init.d/rsyncd restart  # 输出:rsync已重启

如涉及版权问题请联系作者处理!!!

http://www.xdnf.cn/news/18764.html

相关文章:

  • 【数据结构】布隆过滤器的概率模型详解及其 C 代码实现
  • mysql没有mvcc之前遇到了什么问题
  • 2025年AI Agent规模化落地:企业级市场年增超60%,重构商业作业流程新路径
  • Hive中的join优化
  • 基于SpringBoot的招聘系统源码
  • 解决Conda访问官方仓库失败:切换国内镜像源的详细教程
  • STAR-CCM+|K-epsilon湍流模型溯源
  • GEO优化供应商:AI搜索时代的“答案”构建与移山科技的引领,2025高性价比实战指南
  • 基于大模型的对话式推荐系统技术架构设计
  • Linux服务环境搭建指南
  • AI绘画落地难?我用Firefly+Marmoset,将2D概念图“反向工程”为3D游戏资产
  • Deep Unfolding Net(LR到HR)
  • Linux 进程间通信之System V 共享内存
  • react中多个页面,数据相互依赖reducer解决方案
  • 文生3D实战:用[灵龙AI API]玩转AI 3D模型 – 第7篇
  • 青少年机器人技术(四级)等级考试试卷-实操题(2021年12月)
  • Boost.Asio 库中的 async_read_some用法
  • 我从零开始学习C语言(14)- 基本类型 PART1
  • vscode 中自己使用的 launch.json 设置
  • 5.7 生成环境使用cdn加载element ui
  • ASCOMP PDF Conversa:高效精准的PDF转换工具
  • pcie实现虚拟串口
  • 人工智能之数学基础:离散随机变量和连续随机变量
  • Java中如何实现对象的拷贝
  • RHCSA--命令(一)
  • 我是如何写作的?
  • Manus AI 与多语言手写识别技术文章大纲
  • 单例模式与线程池
  • 【Vue✨】Vue 中的 diff 算法详解
  • 云原生概述