在 Linux Shell 编程体系中,条件语句是实现脚本 “智能化” 的核心骨架。它打破了命令串行执行的固定模式,让脚本能够根据文件状态、数值大小、字符串匹配等不同条件,自主选择执行路径,从而完成复杂的逻辑判断与业务处理。无论是简单的目录存在性检查,还是复杂的服务启停控制,条件语句都扮演着 “决策中枢” 的角色。本文基于企业级运维实战需求,以 Shell 条件测试操作为基础,深入拆解if条件语句的单分支、双分支、多分支结构,系统讲解case分支语句的模式匹配逻辑,结合大量原创实操案例,构建一套从基础语法到生产实践的完整学习体系,助力运维人员掌握分支控制核心技术,编写逻辑严谨、灵活高效的 Shell 脚本。

一、Shell 条件测试:分支决策的判断基石

Shell 脚本的条件判断,本质是通过 “条件测试操作” 获取命令的返回状态值($?)—— 返回值为 0 表示条件成立,非 0 则表示条件不成立。所有的条件语句,都是基于这一核心规则构建的。Shell 提供了两种核心测试语法:test 表达式[ 表达式 ](方括号与表达式之间必须保留空格),两者功能完全等价,后者因书写更简洁、可读性更强,成为企业开发的主流选择。

根据测试对象的不同,条件测试可分为文件测试、整数值比较、字符串测试和逻辑测试四大类,覆盖了 Shell 编程中绝大多数判断场景。

(一)文件测试:校验文件系统对象的状态

文件测试是运维脚本中最常用的测试类型,主要用于判断文件或目录的存在性、类型及权限属性,核心操作符与功能如下表所示:

表格

操作符 测试功能 应用示例
-d 测试是否为目录 [ -d /media/cdrom ]
-e 测试文件 / 目录是否存在 [ -e /etc/passwd ]
-f 测试是否为普通文件 [ -f /usr/bin/bash ]
-r 测试当前用户是否有读取权限 [ -r /root/config.conf ]
-w 测试当前用户是否有写入权限 [ -w /var/log/ops.log ]
-x 测试当前用户是否有执行权限 [ -x /root/backup.sh ]

在实际脚本开发中,文件测试常与逻辑操作结合,实现更精准的判断。例如,编写脚本时需先检查备份目录是否存在,不存在则自动创建,核心测试逻辑如下:

bash

运行

BACKUP_DIR=/data/backup
# 测试目录是否不存在,若成立则创建
if [ ! -d $BACKUP_DIR ]; then
    mkdir -p $BACKUP_DIR
    echo "备份目录创建成功:$BACKUP_DIR"
fi

为了提升脚本执行效率,还可使用 “短路逻辑” 简化书写:当条件成立时,直接执行后续命令,否则跳过。例如,测试目录存在则输出提示,可简写为:

bash

运行

[ -d /media/cdrom ] && echo "光盘挂载目录已存在"

(二)整数值比较:实现数值维度的逻辑判断

整数值比较主要用于处理数字相关的判断,如用户数量统计、磁盘使用率阈值检测、进程数量限制等场景。需要注意的是,Shell 不支持直接使用><等符号进行数值比较(这些符号会被解析为重定向操作),必须使用专用的比较操作符,核心操作符如下:

表格

操作符 比较功能 应用场景
-eq 等于 判断两个数值是否相等
-ne 不等于 判断数值是否存在差异
-gt 大于 检测阈值是否超标(如磁盘使用率 > 90%)
-lt 小于 判断剩余空间是否不足(如内存 < 1024MB)
-ge 大于等于 校验软件版本号是否达标
-le 小于等于 限制并发进程数量

实战案例:编写脚本检测当前登录用户数量,若超过 5 人则输出告警信息。核心逻辑通过who | wc -l获取用户数,再与阈值进行比较:

bash

运行

# 获取当前登录用户数量
USER_COUNT=$(who | wc -l)
# 测试用户数是否大于5
if [ $USER_COUNT -gt 5 ]; then
    echo "【告警】当前登录用户数为$USER_COUNT,超过阈值5人!"
else
    echo "当前登录用户数为$USER_COUNT,处于正常范围。"
fi

另一典型场景是内存监控:检测系统可用内存(以 MB 为单位)是否低于 1024MB,若低于则输出告警,核心代码如下:

bash

运行

# 获取可用内存大小(MB)
FREE_MEM=$(free -m | grep "Mem" | awk '{print $4}')
[ $FREE_MEM -lt 1024 ] && echo "【紧急】可用内存仅为${FREE_MEM}MB,低于阈值1024MB!"

(三)字符串测试:处理文本与输入的匹配验证

字符串测试主要用于校验字符串的空值状态、匹配情况,广泛应用于用户输入验证、环境变量检查、配置参数匹配等场景,核心操作符如下:

表格

操作符 测试功能 应用示例
= 字符串相等 验证用户输入的确认指令是否为 "yes"
!= 字符串不相等 检测系统语言是否为 "en_US.UTF-8"
-z 字符串长度为 0(空字符串) 判断用户是否未输入参数
-n 字符串长度不为 0(非空) 校验配置参数是否有效

实战案例:编写交互式脚本,要求用户输入 “yes” 或 “no” 确认是否覆盖文件,若输入非指定值则重新提示。核心逻辑通过字符串测试实现输入校验:

bash

运行

while true; do
    read -p "是否覆盖现有文件(yes/no)?" INPUT
    # 测试输入是否为yes或no
    if [ $INPUT = "yes" ] || [ $INPUT = "no" ]; then
        break
    else
        echo "输入错误,请输入yes或no!"
    fi
done
echo "你选择了:$INPUT"

另一常见场景是环境变量检查:脚本执行前,校验JAVA_HOME环境变量是否存在(非空),若不存在则终止脚本并提示,核心代码如下:

bash

运行

if [ -z $JAVA_HOME ]; then
    echo "【错误】未检测到JAVA_HOME环境变量,请先配置!"
    exit 1
fi
echo "Java环境配置正常,路径:$JAVA_HOME"

(四)逻辑测试:实现多条件的复合判断

在复杂的业务场景中,单一条件往往无法满足判断需求,需要将多个测试条件组合起来,这就需要用到逻辑测试。Shell 提供了三种核心逻辑操作符,分别对应 “与”“或”“非” 三种关系,支持在test[ ]语法中使用,也可直接用于命令之间的逻辑判断。

表格

逻辑关系 操作符(测试语法) 操作符(命令逻辑) 功能描述
逻辑与 -a && 所有条件都成立,整体才成立
逻辑或 -o ` ` 任意一个条件成立,整体即成立
逻辑非 ! ! 条件不成立时,整体成立

需要注意的是,-a-o仅适用于[ ]内部的多条件组合,而&&||可用于连接多个测试命令,书写更灵活,是企业开发的首选方式。

实战案例:编写脚本判断系统内核版本是否符合要求 —— 内核主版本需大于等于 3,次版本需大于等于 10。核心逻辑通过uname -r提取版本号,再结合逻辑与操作实现复合判断:

bash

运行

# 提取内核主版本和次版本
KERNEL_MAJOR=$(uname -r | awk -F. '{print $1}')
KERNEL_MINOR=$(uname -r | awk -F. '{print $2}')

# 复合判断:主版本>=3 且 次版本>=10
if [ $KERNEL_MAJOR -ge 3 ] && [ $KERNEL_MINOR -ge 10 ]; then
    echo "系统内核版本符合要求(当前:$(uname -r))"
else
    echo "【警告】系统内核版本过低(当前:$(uname -r)),建议升级!"
fi

另一案例是文件操作的容错判断:测试文件是否为普通文件且当前用户有读取权限,核心代码如下:

bash

运行

FILE=/etc/hosts
if [ -f $FILE -a -r $FILE ]; then
    echo "文件$FILE存在且具备读取权限,内容如下:"
    cat $FILE
else
    echo "文件$FILE不存在或无读取权限!"
fi

二、if 条件语句:Shell 分支控制的核心框架

if条件语句是 Shell 编程中最灵活、应用最广泛的分支结构,根据条件的复杂程度,可分为单分支、双分支和多分支三种形式。它的核心逻辑是 “如果…… 就……,否则……”,能够根据条件测试的结果,执行不同的命令序列,适配从简单到复杂的各类业务场景。

(一)单分支 if 语句:满足条件才执行的基础逻辑

单分支if语句是最基础的分支结构,仅包含 “条件测试” 和 “命令序列” 两部分,适用于 “条件成立则执行,不成立则跳过” 的场景。

1. 语法结构

bash

运行

if [ 条件测试表达式 ]; then
    命令序列
fi

关键注意事项:if行末尾的分号不可省略;then可与if同行,也可单独换行;fi作为结束标记,必须与if成对出现。

2. 实战案例:自动创建部署目录

场景:编写应用部署脚本,首先检查部署目录/opt/app是否存在,若不存在则创建,并设置权限;若存在则直接提示。

bash

运行

#!/bin/bash
# 脚本名称:create_deploy_dir.sh
# 功能:自动创建应用部署目录

DEPLOY_DIR=/opt/app

# 单分支判断:目录不存在则创建
if [ ! -d $DEPLOY_DIR ]; then
    mkdir -p $DEPLOY_DIR
    chmod 755 $DEPLOY_DIR
    echo "部署目录创建成功:$DEPLOY_DIR,权限已设置为755"
fi

echo "部署目录检查完成,当前状态:已存在"
3. 实战案例:校验脚本执行权限

场景:编写运维脚本,要求必须以root用户执行,若为普通用户则输出错误信息并终止脚本。

bash

运行

#!/bin/bash
# 脚本名称:check_root.sh
# 功能:校验脚本执行用户是否为root

# 单分支判断:非root用户则终止
if [ $USER != "root" ]; then
    echo "【错误】该脚本必须以root用户执行!当前用户:$USER"
    exit 1  # 退出脚本,返回状态码1
fi

echo "用户校验通过,开始执行核心操作..."

(二)双分支 if 语句:二选一的逻辑决策

双分支if语句在单分支的基础上,增加了 “条件不成立时的执行逻辑”,适用于 “二选一” 的判断场景,如 “文件存在则备份,不存在则提示”“服务运行则重启,未运行则启动”。

1. 语法结构

bash

运行

if [ 条件测试表达式 ]; then
    条件成立时执行的命令序列
else
    条件不成立时执行的命令序列
fi
2. 实战案例:远程主机连通性检测

场景:编写脚本,接收一个 IP 地址作为参数,测试该主机是否可连通(通过 ping 命令),并输出检测结果。

bash

运行

#!/bin/bash
# 脚本名称:ping_host.sh
# 功能:检测远程主机连通性
# 使用方法:./ping_host.sh 目标IP

# 校验参数数量
if [ $# -ne 1 ]; then
    echo "用法:$0 目标IP地址"
    exit 1
fi

IP=$1
# 执行ping测试(发送3个包,超时1秒,屏蔽输出)
ping -c 3 -W 1 $IP &> /dev/null

# 双分支判断:根据ping的返回状态判断连通性
if [ $? -eq 0 ]; then
    echo "【成功】主机$IP 网络连通"
else
    echo "【失败】主机$IP 网络不通"
fi
3. 实战案例:服务状态监控与启动

场景:编写脚本,检测vsftpd服务是否运行,若运行则输出状态信息,若未运行则尝试启动该服务。

bash

运行

#!/bin/bash
# 脚本名称:monitor_vsftpd.sh
# 功能:监控并自动启动vsftpd服务

# 检测vsftpd进程是否存在
pgrep vsftpd &> /dev/null

# 双分支判断
if [ $? -eq 0 ]; then
    # 获取服务监听地址和进程ID
    LISTEN=$(netstat -unpt | grep vsftpd | awk '{print $4}')
    PID=$(pgrep vsftpd)
    echo "vsftpd服务运行正常,监听地址:$LISTEN,进程ID:$PID"
else
    echo "vsftpd服务未运行,正在尝试启动..."
    systemctl start vsftpd
    # 再次检测启动结果
    if [ $? -eq 0 ]; then
        echo "vsftpd服务启动成功!"
    else
        echo "【错误】vsftpd服务启动失败,请检查配置!"
    fi
fi

(三)多分支 if 语句:多条件的层级化判断

多分支if语句通过elif(else if 的缩写)实现多个条件的层级化判断,适用于 “存在多个互斥条件,需分别执行不同逻辑” 的场景,如成绩等级判定、系统版本适配、菜单选择处理等。

1. 语法结构

bash

运行

if [ 条件测试表达式1 ]; then
    条件1成立时执行的命令序列
elif [ 条件测试表达式2 ]; then
    条件2成立时执行的命令序列
elif [ 条件测试表达式3 ]; then
    条件3成立时执行的命令序列
...
else
    所有条件都不成立时执行的命令序列
fi

关键特性:条件判断按顺序执行,一旦某个条件成立,将执行对应的命令序列并跳过后续所有判断;若所有条件都不成立,则执行else后的命令序列。

2. 实战案例:考试成绩等级判定

场景:编写交互式脚本,接收用户输入的考试分数(0-100),根据分数区间判定等级:90-100 分为 “优秀”,70-89 分为 “合格”,0-69 分为 “不合格”,同时校验输入是否为有效数字。

bash

运行

#!/bin/bash
# 脚本名称:grade_judge.sh
# 功能:根据考试分数判定成绩等级

read -p "请输入考试分数(0-100):" SCORE

# 第一步:校验输入是否为整数
if ! [[ $SCORE =~ ^[0-9]+$ ]]; then
    echo "【错误】输入无效,请输入0-100之间的整数!"
    exit 1
fi

# 第二步:多分支判断成绩等级
if [ $SCORE -ge 90 ] && [ $SCORE -le 100 ]; then
    echo "你的分数为$SCORE,等级:优秀!"
elif [ $SCORE -ge 70 ] && [ $SCORE -le 89 ]; then
    echo "你的分数为$SCORE,等级:合格!"
elif [ $SCORE -ge 0 ] && [ $SCORE -le 69 ]; then
    echo "你的分数为$SCORE,等级:不合格,请继续努力!"
else
    echo "【错误】分数超出0-100范围!"
fi
3. 实战案例:系统发行版适配

场景:编写脚本,检测当前 Linux 系统的发行版(CentOS、Ubuntu、OpenEuler),并输出对应的包管理命令,适用于跨系统的软件安装脚本。

bash

运行

#!/bin/bash
# 脚本名称:check_distro.sh
# 功能:检测系统发行版并输出包管理命令

# 读取系统发行版信息
DISTRO=$(cat /etc/os-release | grep "ID=" | head -1 | awk -F= '{print $2}' | sed 's/"//g')

# 多分支判断
if [ $DISTRO = "centos" ] || [ $DISTRO = "rocky" ]; then
    echo "当前系统为:RedHat系($DISTRO),包管理命令:yum/dnf"
elif [ $DISTRO = "ubuntu" ] || [ $DISTRO = "debian" ]; then
    echo "当前系统为:Debian系($DISTRO),包管理命令:apt/apt-get"
elif [ $DISTRO = "openeuler" ]; then
    echo "当前系统为:OpenEuler,包管理命令:dnf"
else
    echo "当前系统为:$DISTRO,暂不支持的发行版!"
fi

三、case 分支语句:模式匹配的高效分支方案

在处理 “单个变量的多值匹配” 场景时,多分支if语句会因条件过多导致代码冗余、可读性下降。而case分支语句通过 “模式匹配” 的方式,能够快速匹配变量的不同取值,执行对应的命令序列,特别适用于菜单交互、服务启停控制、参数解析等场景,代码结构更简洁、执行效率更高。

(一)case 语句的核心语法与匹配规则

1. 基本语法结构

bash

运行

case 变量值 in
模式1)
    命令序列1
    ;;
模式2)
    命令序列2
    ;;
模式3)
    命令序列3
    ;;
*)
    默认命令序列
    ;;
esac
2. 关键匹配规则
  1. 模式格式:支持精确匹配(如start1)、通配符匹配(*匹配任意字符,?匹配单个字符,[a-z]匹配字符范围);
  2. 终止标记:每个模式对应的命令序列,必须以;;结束,表示跳出case语句;
  3. 匹配顺序:按模式书写顺序依次匹配,一旦匹配成功,立即执行对应命令序列并终止判断;
  4. 默认匹配*)作为最后一个模式,匹配所有未命中的情况,实现 “兜底” 处理。

(二)实战案例一:交互式字符类型判断

场景:编写脚本,接收用户输入的单个字符,通过case语句判断其为字母、数字还是特殊字符(空格、功能键等),并输出提示信息。

bash

运行

#!/bin/bash
# 脚本名称:char_type.sh
# 功能:判断输入字符的类型

read -p "请输入一个字符,按Enter键确认:" KEY

# 提取第一个字符(避免用户输入多字符)
CHAR=${KEY:0:1}

case $CHAR in
# 匹配字母(大小写)
[a-zA-Z])
    echo "你输入的是:字母"
    ;;
# 匹配数字
[0-9])
    echo "你输入的是:数字"
    ;;
# 匹配特殊字符(此处匹配空格,其他特殊字符可扩展)
" ")
    echo "你输入的是:空格"
    ;;
# 默认匹配:其他所有字符
*)
    echo "你输入的是:特殊字符或功能键"
    ;;
esac

(三)实战案例二:自定义服务控制脚本

场景:模仿 Linux 系统服务的控制逻辑,编写myapp服务的控制脚本,支持startstoprestartstatus四种参数,实现服务的启停、重启与状态查询,核心逻辑通过case语句实现参数匹配。

bash

运行

#!/bin/bash
# 脚本名称:myapp.sh
# 功能:自定义服务控制脚本
# 使用方法:./myapp.sh [start|stop|restart|status]

# 定义服务进程名称(实际场景替换为真实服务名)
APP_NAME="sleep"
# 定义服务启动命令
START_CMD="sleep 3600 &"

# 校验参数数量
if [ $# -ne 1 ]; then
    echo "用法:$0 [start|stop|restart|status]"
    exit 1
fi

# case分支匹配参数
case $1 in
start)
    # 先检测服务是否已运行
    pgrep $APP_NAME &> /dev/null
    if [ $? -eq 0 ]; then
        echo "【提示】$APP_NAME服务已处于运行状态!"
    else
        echo -n "正在启动$APP_NAME服务..."
        eval $START_CMD
        sleep 1
        if [ $? -eq 0 ]; then
            echo "成功!"
        else
            echo "失败!"
        fi
    fi
    ;;

stop)
    pgrep $APP_NAME &> /dev/null
    if [ $? -ne 0 ]; then
        echo "【提示】$APP_NAME服务未运行!"
    else
        echo -n "正在停止$APP_NAME服务..."
        pkill $APP_NAME &> /dev/null
        sleep 1
        echo "完成!"
    fi
    ;;

restart)
    echo "正在重启$APP_NAME服务..."
    # 调用stop和start逻辑
    $0 stop
    $0 start
    ;;

status)
    pgrep $APP_NAME &> /dev/null
    if [ $? -eq 0 ]; then
        PID=$(pgrep $APP_NAME)
        echo "$APP_NAME服务运行正常,进程ID:$PID"
    else
        echo "$APP_NAME服务未运行!"
    fi
    ;;

*)
    echo "【错误】无效参数!用法:$0 [start|stop|restart|status]"
    exit 1
    ;;
esac

(四)实战案例三:菜单式运维工具

场景:编写菜单式脚本,实现 “系统信息查询”“磁盘监控”“服务管理”“退出” 四项功能的交互选择,通过case语句处理用户的菜单选择,提升脚本的交互性与实用性。

bash

运行

#!/bin/bash
# 脚本名称:ops_menu.sh
# 功能:Linux运维常用工具菜单

while true; do
    # 清屏并打印菜单
    clear
    echo "==================== Linux运维工具菜单 ===================="
    echo "1. 查看系统核心信息(内核、CPU、内存)"
    echo "2. 检测磁盘分区使用率"
    echo "3. 管理vsftpd服务(启动/停止/状态)"
    echo "4. 退出脚本"
    echo "=========================================================="
    read -p "请输入你的选择(1-4):" CHOICE

    # case匹配菜单选择
    case $CHOICE in
    1)
        echo -e "\n【系统核心信息】"
        echo "内核版本:$(uname -r)"
        echo "CPU型号:$(lscpu | grep "Model name" | awk -F: '{print $2}' | sed 's/^ //')"
        echo "内存总量:$(free -g | grep "Mem" | awk '{print $2}')GB"
        read -p "按Enter键返回菜单..."
        ;;
    2)
        echo -e "\n【磁盘分区使用率】"
        df -h | grep -E "sd|vda"
        read -p "按Enter键返回菜单..."
        ;;
    3)
        read -p "请输入vsftpd操作(start/stop/status):" FTP_OP
        case $FTP_OP in
        start|stop|status)
            systemctl $FTP_OP vsftpd
            echo "操作结果:$?"
            ;;
        *)
            echo "无效操作,请输入start、stop或status!"
            ;;
        esac
        read -p "按Enter键返回菜单..."
        ;;
    4)
        echo "感谢使用,脚本退出!"
        exit 0
        ;;
    *)
        echo "输入错误,请输入1-4之间的数字!"
        sleep 2
        ;;
    esac
done

四、条件语句运维最佳实践与故障排查

(一)核心最佳实践

  1. 语法规范
    • 条件测试中,[ ]与表达式之间必须保留空格,避免出现[$VAR -eq 10]的错误;
    • ifelifelseficaseesac关键字需单独成行(或按语法要求换行),提升代码可读性;
    • 复杂脚本中,使用缩进(4 个空格)区分代码块,清晰展示分支层级。
  2. 容错设计
    • 脚本执行前,先校验参数数量、参数有效性,避免因参数错误导致分支判断异常;
    • 关键条件判断后,增加二次校验(如服务启动后,再次检测进程是否存在),确保操作生效。
  3. 性能优化
    • 优先使用&&||实现简单的条件执行,替代冗余的单分支if语句;
    • case语句优先用于多值匹配场景,相比多分支if,执行效率更高、代码更简洁。
  4. 可维护性
    • 复杂的条件测试表达式,可通过定义变量简化,如IS_ROOT="[ $USER = 'root' ]"
    • 分支内的核心逻辑,可封装为函数,避免代码冗余,便于后续维护。

(二)常见故障排查

  1. 条件测试返回值异常
    • 排查是否使用了错误的操作符(如用=进行数值比较,用-eq进行字符串比较);
    • 检查变量是否被正确赋值,避免因变量为空导致测试失败。
  2. 脚本执行时提示 “语法错误”
    • 检查if行末尾是否遗漏分号,then是否书写正确;
    • 确认case语句中,每个模式的命令序列是否以;;结束,esac是否遗漏。
  3. case 语句匹配失效
    • 检查变量值与模式是否完全匹配(如变量包含空格,模式未加引号);
    • 确认模式书写顺序,避免通配符模式(如*)出现在前面,导致后续精确模式无法匹配。
  4. 分支逻辑执行异常
    • 多分支if语句中,检查条件是否存在重叠(如先判断-ge 50,再判断-ge 80);
    • 脚本中使用set -x开启调试模式,逐行查看命令执行过程与变量值,定位逻辑错误。

五、总结

条件语句是 Shell 脚本从 “简单命令拼接” 到 “复杂逻辑实现” 的关键跨越,而条件测试操作则是分支决策的基础。本文系统阐述了文件测试、整数值比较、字符串测试、逻辑测试四大类测试方法,详细拆解了if语句的单分支、双分支、多分支结构,深入讲解了case语句的模式匹配规则与实战应用,并通过大量原创的企业级案例,将语法知识与运维实践紧密结合。

在实际工作中,if语句与case语句并非相互排斥,而是可以灵活结合:对于复杂的复合条件判断,优先使用if语句;对于单个变量的多值匹配,优先使用case语句。运维人员在编写脚本时,应遵循语法规范,做好容错设计,兼顾代码的可读性、效率与可维护性。

掌握 Shell 条件语句,不仅能实现日常运维任务的自动化,更能构建出逻辑严谨、适配复杂场景的运维工具。随着实战经验的积累,结合后续的循环语句、函数等知识,将能够编写更加强大的 Shell 脚本,全面提升 Linux 系统运维的自动化水平与工作效率。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐