Linux Shell编程及自动化运维实现-2-判断

无论什么编程语言都离不开条件判断。SHELL 也不例外。

例如,用户输入的密码不够长时提示”太短了”;用户输入了备份的目录,如果有目录继续备份,如果没有目录则创建目录;用户输入成绩,100-80 分评为优秀,60-79 分评为合格,59-0 分评为不合格。

本文将系统讲解 Shell 条件测试(数值、文件、字符串)、逻辑运算、if 流程控制、case 模式匹配,并通过实战案例带你掌握判断与流控的完整知识体系。


条件测试

基础格式

if [ 条件表达式 ]; then
    # 条件为真时执行的命令
fi


# 方括号 [ ] 两边必须有空格,否则会报语法错误
#条件表达式中的变量建议用双引号包裹,防止空格或特殊字符导致解析错误
# 分号 ; 是命令分隔符,如果 then 写在新行,可以省略分号:

if [ 条件表达式 ]
then
    # 命令
fi

数值比较

语法:[ 整数1 操作符 整数2 ]

操作符说明示例结果
-gt大于(greater than)[ 20 -gt 10 ]true
-lt小于(less than)[ 1 -lt 10 ]true
-eq等于(equal)[ 1 -eq 1 ]true
-ne不等于(not equal)[ 1 -ne 10 ]true
-ge大于等于(greater or equal)[ 20 -ge 10 ]true
-le小于等于(less or equal)[ 10 -le 10 ]true

获取变量长度的方法:

pass="hello"
echo ${#pass}    # 输出 5

三种条件测试语法:

格式语法说明
格式 1test 条件表达式最传统的写法
格式 2[ 条件表达式 ]最常用,注意方括号内两侧必须有空格
格式 3[[ 条件表达式 ]]Bash 扩展语法,支持正则表达式等高级功能

密码长度测试案例

需求:猜测用户输入的密码,是否满足长度需求(至少 7 位)。

[root@localhost ~]# vim pass1.sh

#!/bin/bash
read -p "请输入您的密码:" ps

if [ ${#ps} -lt 7 ]; then
    echo "您的密码太短!"
else
    echo "您的密码真长!"
fi

测试:

[root@localhost ~]# bash pass1.sh
请输入您的密码:123
您的密码太短!

[root@localhost ~]# bash pass1.sh
请输入您的密码:1234567
您的密码真长!

文件测试

语法:[ 操作符 文件或目录 ]

操作符(了解)说明
-f文件存在且为普通文件
-d目录存在
-e文件或目录存在
-r文件可读
-w文件可写
-x文件可执行
-s文件存在且大小大于 0
-b文件存在且是块文件
-c文件存在且是字符文件
-h-L文件存在且是符号链接
-g文件存在并且设置了 SGID 位
-k文件存在并且设置了”粘滞”位
-p文件存在且是命名管道
-S文件存在且是 socket
-t fdfd 是与终端设备相关联的文件描述符
-O文件存在并且被当前进程的有效用户拥有
-G文件存在并且属于当前进程的有效用户的用户组

目录存在性测试案例

需求:请用户输入备份的路径,如果存在提示已存在可以备份,如果不存在提示目录不存在请创建。

[root@localhost ~]# vim path.sh

#!/bin/bash
read -p "请您输入备份的目录:" dir1

if [ -d "$dir1" ]; then
    echo "$dir1 存在可以备份"
else
    echo "$dir1 不存在无法备份"
fi

测试:

[root@localhost ~]# mkdir /abc

[root@localhost ~]# bash path.sh
请您输入备份的目录:/abc
/abc 存在可以备份

[root@localhost ~]# bash path.sh
请您输入备份的目录:/def
/def 不存在无法备份

字符串比较

语法:[ "字符串" = "字符串" ]

操作符说明示例
=等于[ "$a" = "yes" ]
!=不等于(注意叹号和等号间没有空格)[ "$a" != "no" ]
-z判断字符长度是否为 0[ -z "$str" ]
-n判断字符长度是否不为 0[ -n "$str" ]

字符串相等测试案例

需求:邀请用户确认,yes 升级装备,no 不升级装备。

[root@localhost ~]# vim yes.sh

#!/bin/bash
read -p "您确定要升级这件装备吗?" select

if [ "$select" = "yes" ]; then
    echo "装备升级开始。。。"
else
    echo "感谢您,欢迎下次光临。"
fi

测试:

[root@localhost ~]# bash yes.sh
您确定要升级这件装备吗?yes
装备升级开始。。。

[root@localhost ~]# bash yes.sh
您确定要升级这件装备吗?no
感谢您,欢迎下次光临。

双引号的重要性

双引号在字符串比较中非常重要,可以解决变量为空时的”一元表达式”错误。

[root@localhost ~]# BBB=""
[root@localhost ~]# echo ${#BBB}
0

# 使用双引号:正确
[root@localhost ~]# [ -z "$BBB" ]    # 判断字符长度是否为 0
[root@localhost ~]# echo $?
0

[root@localhost ~]# [ -n "$BBB" ]    # 判断字符长度是否不为 0
[root@localhost ~]# echo $?
1

# 不使用双引号:可能报错
[root@localhost ~]# [ -z $BBB ]
# 如果 BBB 为空,表达式变成 [ -z ],会报错

关键:在条件测试中使用变量时,务必加上双引号 "$变量",避免变量为空时产生语法错误。


逻辑运算(AND / OR)

简介

当条件测试比较复杂时,需要多个条件同时成立。就需要混合条件测试了。

符号含义说明
&&-a逻辑 AND两个条件同时成立,为真
`-o`

多种表达方法:

# 使用 -a 和 -o(在 [] 中)
[root@localhost ~]# [ 1 -lt 2 -a 5 -gt 10 ]    # AND
[root@localhost ~]# [ 1 -lt 2 -o 5 -gt 10 ]    # OR

# 使用 && 和 ||(在 [[]] 中)
[root@localhost ~]# [[ 1 -lt 2 && 5 -gt 10 ]]  # AND
[root@localhost ~]# [[ 1 -lt 2 || 5 -gt 10 ]]  # OR

# 使用多个 [] 组合
[root@localhost ~]# [ 1 -lt 2 ] && [ 11 -gt 10 ]  # AND

复杂密码验证案例

需求:猜测用户输入的密码是否满足如下条件:

  1. 长度大于等于 7 位
  2. 包含字母大写
  3. 包含字母小写
  4. 包含符号 @_!
[root@localhost ~]# vim pass3.sh

#!/bin/bash
read -p "请您输入新密码: " pass

if [ ${#pass} -ge 7 ] && [[ ${pass} =~ [a-z] ]] && [[ ${pass} =~ [A-Z] ]] && [[ ${pass} =~ [@_!] ]]; then
    echo "您的密码真复杂!!!"
else
    echo "您的密码太简单!!!"
fi

测试:

[root@localhost ~]# bash pass3.sh
请您输入新密码: 1234567
您的密码太简单!!!

[root@localhost ~]# bash pass3.sh
请您输入新密码: 1234567a
您的密码太简单!!!

[root@localhost ~]# bash pass3.sh
请您输入新密码: 1234567aZ
您的密码太简单!!!

[root@localhost ~]# bash pass3.sh
请您输入新密码: 123456aZ@
您的密码真复杂!!!

[root@localhost ~]# bash pass3.sh
请您输入新密码: 12345aZ!
您的密码真复杂!!!

注意:密码验证时要注意中文输入法的符号问题,中文符号和英文符号是不同的。


流程控制:if

单分支结构

语法:

if [ 条件测试 ]; then
    符合该条件执行的语句
fi

示例:创建不存在的用户

#!/bin/bash

read -p "请输入用户名: " name

id $name &>/dev/null

if [ $? -ne 0 ]; then
    useradd $name
fi

$? 变量说明

$? 包含了之前执行命令的退出状态。0 表示成功,非零表示失败。


双分支结构

语法:

if [ 条件表达式 ]; then
    # 条件为真时执行的命令
else
    # 条件为假时执行的命令
fi

示例:创建用户并设置密码

#!/bin/bash

read -p "请输入用户名: " name

if id $name &>/dev/null; then
    echo "$name 已存在"
else
    useradd $name
    echo "123456" | passwd --stdin $name &>/dev/null
    echo "$name 创建完成, 密码为 123456"
fi

注意:if id $name &>/dev/null; then 这种写法将条件测试直接放在了 if 后面,比使用 $? 更简洁。


多分支结构

语法:

if [ 条件表达式1 ]; then
    # 条件1为真时执行
elif [ 条件表达式2 ]; then
    # 条件1为假、条件2为真时执行
elif [ 条件表达式3 ]; then
    # 条件1、2为假、条件3为真时执行
·
·
·
else
    # 所有条件都为假时执行
fi

示例:根据系统时间判断时段

#!/bin/bash

hour=$(date +%H)

if [ $hour -ge 6 -a $hour -le 10 ]; then
    echo "This is morning"
elif [ $hour -ge 11 -a $hour -le 13 ]; then
    echo "This is noon"
elif [ $hour -ge 14 -a $hour -le 18 ]; then
    echo "This is afternoon"
else
    echo "This is night"
fi

嵌套结构

语法:

if [ 条件表达式1 ]; then
    if [ 条件表达式2 ]; then
        # 条件1和条件2都为真时执行
    fi
else
fi

示例:创建用户并验证密码

#!/bin/bash

read -p "请输入用户名: " name

id $name &>/dev/null

if [ $? -eq 0 ]; then
    echo "$name 存在"
else
    useradd $name
    echo "$name 创建成功"

    read -p "请输入用户密码: " pass

    if [ ${#pass} -ge 7 ]; then
        echo "$pass" | passwd --stdin $name
        echo "$name 用户密码是 $pass"
    else
        echo "密码不合格"
    fi
fi

调试脚本

# 仅调试脚本中的语法错误
sh -n script.sh

# 以调试的方式执行,查询整个执行过程
sh -vx script.sh
选项说明
-n读取脚本,检查语法错误,但不执行
-v显示读取的每一行
-x显示执行的每一行命令及其参数

注意事项

  1. 空格很重要[ ] 表示条件测试,要注意在 [ 后面和 ] 前面都必须有空格
  2. then 和 fi 要分开:在 shell 中,then 和 fi 是分开的语句。如果要在同一行里面输入,则需要用分号将它们隔开:if [ 条件 ]; then ; fi
  3. 变量加引号:if 判断中对于变量的处理,需要加引号,以免一些不必要的错误。没有加双引号会在一些含空格等的字符串变量判断的时候产生错误。比如 [ -n "$var" ],如果 var 为空不加引号会出错
  4. 不支持浮点值:判断是不支持浮点值的,需要使用 bc 等工具
  5. >< 要转义:如果只单独使用 > 或者 < 号,系统会认为是输出或者输入重定向,虽然结果显示正确,但是其实是错误的,因此要对这些符号进行转义
  6. 错误信息默认输出:运行 if 语句中的命令所产生的错误信息,仍然出现在脚本的输出结果中
  7. -z-n 检查未定义变量:使用 -z 或者 -n 来检查长度的时候,没有定义的变量也为 0
  8. 空变量可能造成灾难性影响:空变量和没有初始化的变量可能会对 shell 脚本测试产生灾难性的影响,因此在不确定变量的内容的时候,在测试号前使用 -n 或者 -z 测试一下
  9. $? 变量:包含了之前执行命令的退出状态(最近完成的前台进程),可以用于检测退出状态

模式匹配:case

前言

Shell 编程中,ifcase 都是用来做流程控制的。

if 的局限性:当需要匹配多个值时(如 yYyesYES 等),if 语句会变得非常冗长。


case 语法

case 变量 in
    模式1)
        命令序列1
        ;;
    模式2)
        命令序列2
        ;;
    模式3)
        命令序列3
        ;;
    *)
        无匹配后执行的命令序列
        ;;
esac
符号说明
;;相当于 break,结束当前模式匹配
*通配符,相当于 else,匹配所有未指定的情况
``

案例 1:简单的模式匹配

需求:邀请用户输入待删除用户名,确认是否删除(支持多种输入)。

if 写法:

#!/bin/bash

read -p "请输入要删除的用户名 : " user
read -p "你确定删除该用户吗?[y/n]: " action

if [ "$action" = "y" -o "$action" = "Y" ]; then
    userdel -r $user
    echo "$user 已删除!"
else
    echo "已退出,谢谢使用"
fi

case 写法:

#!/bin/bash

read -p "请输入要删除的用户名 : " user
read -p "确认删除吗?[yes/no] " action

case "$action" in
    Y|y|YES|yes|Yes|YeS|YEs)
        userdel -r $user
        echo "$user 已删除!"
        ;;
    *)
        echo "已退出,谢谢使用"
        ;;
esac

对比:case 写法更加简洁、易读,特别是需要匹配多个值时。


案例 2:简单的 JumpServer(跳板机)

需求:通过 shell 编程,编写跳板程序。当我们需要访问服务器时,看一眼服务器列表名,按一下数字,就登录成功了。

先配置免密登录

#!/usr/bin/bash

# 定义目标主机 IP
web1=192.168.100.120
web2=192.168.100.123
mysql1=192.168.100.124

# 打印跳转菜单
cat <<EOF
1. WEB1
2. WEB2
3. MYSQL1
EOF

# 读取用户输入
read -p "请输入需要连接的服务器序号: " num

# 判断用户选择
case $num in
    1)
        ssh root@$web1
        ;;
    2)
        ssh root@$web2
        ;;
    *)
        echo "无效输入"
        ;;
esac

使用效果:

[root@localhost ~]# bash ssh.sh 
1. WEB1
2. WEB2
3. MYSQL1
请输入需要连接的服务器序号: 2
Last login: Mon Jun  8 11:32:22 2026 from www.ceshi.com
[root@web2 ~]# 

案例 3:系统管理工具箱

需求:Linux 提供了丰富的管理命令——用户管理、内存管理、磁盘管理、进程管理、日志管理、文件管理、软件管理、网络管理等等。通过 shell 编程,把它们编写到一个程序里。想用某些功能,只需要按回车,就能完成。

菜单选项:

按键功能命令
h显示命令帮助显示菜单
f显示磁盘分区fdisk -l
d显示磁盘挂载df -hT
m查看内存使用free -m
u查看系统负载uptime
q退出程序exit

实现脚本:

#!/usr/bin/bash

# 打印菜单
cat <<-EOF
h. 帮助
f. 磁盘分区信息
d. 文件系统挂载
m. 内存使用情况
u. 系统负载
q. 退出
EOF

# 读取用户输入,进行模式匹配
read -p "请输入选项 [h 查看帮助]: " action

case "$action" in
    f)
        fdisk -l
        ;;
    d)
        df -hT
        ;;
    m)
        free -m
        ;;
    u)
        uptime
        ;;
    q)
        exit
        ;;
    "")
        # 用户直接按回车,不做任何操作
        ;;
    *)
        echo "输入错误,请输入正确的选项"
        ;;
esac

使用效果:

h. 帮助
f. 磁盘分区信息
d. 文件系统挂载
m. 内存使用情况
u. 系统负载
q. 退出
请输入选项 [h 查看帮助]: m
              total        used        free      shared  buff/cache   available
Mem:           3771         118        3438          11         214        3407
Swap:          2047           0        2047

if vs case 对比

对比维度ifcase
适用场景范围判断、数值比较、条件复杂模式匹配、多值判断
语法复杂度多条件时需要多个 elif多模式时更简洁
可读性条件多时难以阅读模式清晰,易于维护
匹配方式精确的条件表达式通配符模式匹配

选择建议

  • 需要判断范围、数值比较、多条件组合时 → 使用 if
  • 需要匹配多个具体值、菜单选择时 → 使用 case

常见问题

[ ][[ ]] 的区别

特性[ ][[ ]]
兼容性POSIX 标准,所有 Shell 都支持Bash 扩展,仅 Bash 支持
正则表达式不支持支持 =~ 运算符
逻辑运算符使用 -a-o使用 &&||
变量为空时不加引号会报错更宽容,不易出错

if 条件中的 then 可以写在同一行吗?

可以,但需要用分号隔开:

if [ 条件 ]; then
    命令
fi

如何调试 if 脚本?

# 检查语法错误
sh -n script.sh

# 查看执行过程
sh -vx script.sh

$? 变量什么时候会被覆盖?

每执行一个命令,$? 都会被更新。所以如果要保留之前的退出状态,应该立即将其保存到变量中:

command
status=$?
echo $status

最佳实践

  1. 始终使用双引号包裹变量


    if [ -n "$var" ]; then

  2. 优先使用 [[ ]] 替代 [ ]


    if [[ "$str" =~ [a-z] ]]; then

  3. 多值匹配使用 case 替代冗长的 if-elif


    case "$action" in
    y|Y|yes|YES) ... ;;

  4. 使用 $(date +%H) 替代反引号


    hour=$(date +%H)  # 推荐
    hour=`date +%H` # 不推荐

  5. 使用 id user 替代 /etc/passwd 检查用户


    if id $name &>/dev/null; then

  6. 多分支 if 注意条件顺序

    • 将最常见的条件放在前面,提高执行效率

总结

通过本章节的学习,你应该掌握了:

  • 理解条件判断在 Shell 编程中的重要性
  • 掌握三种条件测试语法(test、[ ][[ ]]
  • 掌握数值比较操作符(-gt、-lt、-eq、-ne、-ge、-le)
  • 掌握文件测试操作符(-f、-d、-e、-r、-w、-x 等)
  • 掌握字符串比较操作符(=、!=、-z、-n)
  • 理解逻辑运算(AND/OR)的多种表达方式
  • 掌握 if 单分支、双分支、多分支、嵌套结构
  • 掌握 case 模式匹配的语法和用法
  • 理解 if 和 case 的区别和适用场景
  • 掌握脚本调试方法(sh -n、sh -vx)
  • 能够编写密码验证、用户创建、跳板机、系统管理工具箱等实用脚本

学习建议:判断和流程控制是 Shell 编程的核心。建议在虚拟机上动手练习每一个示例,特别是条件测试中的空格问题和双引号的重要性。if 和 case 的区别要理解清楚,在实际开发中根据场景选择合适的流控方式。


🙋 学习路上不孤单,有坑一起填!



卡在参数调试、命令打架、功能没反应、资源失效?其他问题?直接戳我,也可以进群和同好交流!



📱 个人QQ:3838586495    👥 交流Q群:1094091455    📮 邮箱:leyan2504@163.com



内容帮你省了大把踩坑时间?可以文末小小打赏鼓励一波,也欢迎安利给身边学习的朋友~



✨ 欢迎来评论区「交作业」:分享你的配置思路、提出疑难问题;评论区正确填写邮箱,不错过任何人的解答回复!


暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇