Shell 脚本判断

Shell 脚本判断

一、条件测试基础

在 Shell 脚本中,“判断” 的核心是通过条件测试判断表达式真假,进而控制程序流程。条件测试的核心要素包括:测试类型、表达式格式、结果判断逻辑。

1. 条件测试的 3 种类型

Shell 支持三类常见的条件测试,覆盖整数、字符、文件场景:

测试类型

作用

核心场景

整数测试

比较两个整数的大小关系(相等、大于、小于等)

数值比较(如参数数量判断、年龄 / 分数比较)

字符测试

检查字符串的内容、长度或等值关系

字符串是否为空、输入内容匹配(如用户名验证)

文件测试

检测文件 / 目录的存在性、类型、权限、大小等

文件是否存在、是否为目录、是否有执行权限

2. 条件测试的 3 种表达式格式

所有条件测试均需通过固定格式的表达式实现,三种格式功能等价,可根据场景选择:

表达式格式

语法示例

说明

test 条件

test -e /tmp/file

最原始的格式,兼容性好

[ 条件 ]

[ -e /tmp/file ]

简化格式,需注意条件前后有空格(否则语法错误)

[[ 条件 ]]

[[ -e /tmp/file ]]

Bash 扩展格式,支持正则匹配(如 [[ $str =~ ^[0-9]+$ ]]),推荐使用

3. 结果判断逻辑

条件测试的结果通过退出状态码(0 为真,非 0 为假)表示,通常结合逻辑运算符 &&(真则执行)和 ||(假则执行)输出结果:

# 示例:测试 /tmp/file 是否存在

test -e /tmp/file && echo "文件存在" || echo "文件不存在"

[ -e /tmp/file ] && echo "文件存在" || echo "文件不存在"

[[ -e /tmp/file ]] && echo "文件存在" || echo "文件不存在"
  • 若 /tmp/file 存在,输出 文件存在;若不存在,输出 文件不存在。

二、整数测试(数值比较)

整数测试用于比较两个整数的大小关系,需使用专用的比较运算符(不可用 > < 等符号,避免与字符比较混淆)。

1. 整数测试运算符

运算符

含义

示例(判断 $a 和 $b 的关系)

-eq

等于(equal)

[[ $a -eq $b ]] → 判断 $a 是否等于 $b

-ne

不等于(not equal)

[[ $a -ne $b ]] → 判断 $a 是否不等于 $b

-gt

大于(greater than)

[[ $a -gt $b ]] → 判断 $a 是否大于 $b

-ge

大于等于(greater or equal)

[[ $a -ge $b ]] → 判断 $a 是否大于等于 $b

-lt

小于(less than)

[[ $a -lt $b ]] → 判断 $a 是否小于 $b

-le

小于等于(less or equal)

[[ $a -le $b ]] → 判断 $a 是否小于等于 $b

2. 整数测试实战案例

以下三个案例分别实现 “命令行传参比较”“交互式输入比较”“if 多分支比较”,覆盖整数测试的常见场景。

案例 1:命令行传递参数比较

需求:接收两个命令行参数,先判断参数数量是否为 2,再判断是否为整数,最后比较大小。

#!/bin/bash

# 脚本名:a.sh

# 1. 判断参数数量是否为 2

if [[ $# -ne 2 ]]; then

echo "错误:必须输入两个参数"

exit 1 # 非 0 退出码表示执行失败

fi

# 2. 判断参数是否为整数(利用 expr 计算,非整数会报错)

expr $1 + $2 > /dev/null 2>&1 # 重定向错误输出,避免干扰

if [[ $? -ne 0 ]]; then # $? 是上一条命令的退出码(0 为真,非 0 为假)

echo "错误:输入的参数必须是整数"

exit 1

fi

# 3. 比较两个整数的大小

if [[ $1 -gt $2 ]]; then

echo "$1 大于 $2"

elif [[ $1 -lt $2 ]]; then

echo "$1 小于 $2"

else

echo "$1 等于 $2"

fi

执行示例:

sh a.sh 10 20 → 10 小于 20

sh a.sh 20 10 → 20 大于 10

sh a.sh 15 15 → 15 等于 15

sh a.sh 10 → 错误:必须输入两个参数

sh a.sh 10 abc → 错误:输入的参数必须是整数
案例 2:交互式输入参数比较

需求:通过 read 命令让用户交互式输入两个整数,再比较大小。

#!/bin/bash

# 脚本名:c.sh

# 1. 交互式输入两个参数

read -p "请输入要比较的第一个整数:" num1

read -p "请输入要比较的第二个整数:" num2

# 2. 判断是否为整数

expr $num1 + $num2 > /dev/null 2>&1

if [[ $? -ne 0 ]]; then

echo "错误:输入的必须是整数"

exit 1

fi

# 3. 比较大小

[[ $num1 -gt $num2 ]] && echo "$num1 大于 $num2"

[[ $num1 -lt $num2 ]] && echo "$num1 小于 $num2"

[[ $num1 -eq $num2 ]] && echo "$num1 等于 $num2"
  • 执行示例:
sh c.sh

请输入要比较的第一个整数:5

请输入要比较的第二个整数:8

5 小于 8
案例 3:多分支选择(英雄选择)

需求:让用户选择英雄编号(1-3),根据选择输出对应结果,输入其他编号提示 “选择无效”。

#!/bin/bash

# 脚本名:d.sh

# 1. 显示英雄列表

echo "===== 选择你的英雄 ====="

cat <<EOF

1. 全民偶像:鹿晗

2. 综艺之神:陈赫

3. 魔童:邓超

EOF

# 2. 接收用户输入

read -p "请输入英雄编号(1-3):" num

# 3. 多分支判断(结合整数测试和逻辑或 `-o`)

if [[ $num -eq 1 -o $num -eq 2 -o $num -eq 3 ]]; then

if [[ $num -eq 1 ]]; then

echo "已选择:全民偶像 · 鹿晗!"

elif [[ $num -eq 2 ]]; then

echo "已选择:综艺之神 · 陈赫!"

else

echo "已选择:魔童 · 邓超!"

fi

else

echo "错误:你选择了无效的英雄编号!"

fi
  • 执行示例:
sh d.sh

===== 选择你的英雄 =====

1. 全民偶像:鹿晗

2. 综艺之神:陈赫

3. 魔童:邓超

请输入英雄编号(1-3):2

已选择:综艺之神 · 陈赫!

三、字符测试(字符串比较)

字符测试用于检查字符串的内容等值长度是否为空,需注意字符串需加引号(避免空格或特殊字符导致解析错误)。

1. 字符测试运算符

运算符

含义

示例(判断字符串 $str 或 $str1 与 $str2 的关系)

==

等值比较(内容完全一致)

[[ "$str1" == "$str2" ]] → 判断两个字符串是否相同

!=

不等值比较(内容不同)

[[ "$str1" != "$str2" ]] → 判断两个字符串是否不同

-z

字符串为空(长度为 0)

[[ -z "$str" ]] → 判断 $str 是否为空

-n

字符串非空(长度 > 0)

[[ -n "$str" ]] → 判断 $str 是否非空

2. 字符测试实战案例

案例:用户名验证

需求:让用户输入用户名,判断是否为空、是否为指定用户名(如 admin)。

#!/bin/bash

# 脚本名:e.sh

# 1. 接收用户名输入

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

# 2. 判断用户名是否为空

if [[ -z "$username" ]]; then

echo "错误:用户名不能为空!"

exit 1

fi

# 3. 判断用户名是否为 admin

if [[ "$username" == "admin" ]]; then

echo "欢迎你,管理员 $username!"

else

echo "欢迎你,普通用户 $username!"

fi
  • 执行示例:
sh e.sh

请输入用户名:admin → 欢迎你,管理员 admin!

sh e.sh

请输入用户名:zhangsan → 欢迎你,普通用户 zhangsan!

sh e.sh

请输入用户名:(直接回车)→ 错误:用户名不能为空!

四、文件测试(文件 / 目录属性判断)

文件测试是 Shell 脚本中最常用的判断场景,用于检测文件 / 目录的存在性、类型、权限、大小等属性,需使用专用的文件测试运算符。

1. 文件测试运算符分类

根据测试目标,文件测试运算符可分为 6 类,覆盖所有常见文件属性:

(1)存在性测试

运算符

含义

示例

-e

测试文件 / 目录是否存在

[[ -e /tmp/file ]] → 判断 /tmp/file 是否存在

(2)类型测试(存在且为指定类型)

运算符

含义

示例

-f

普通文件(非目录 / 链接)

[[ -f /tmp/file ]] → 判断是否为普通文件

-d

目录

[[ -d /tmp/dir ]] → 判断是否为目录

-L

符号链接文件

[[ -L /tmp/link ]] → 判断是否为软链接

-b

块设备文件(如磁盘 /dev/sda)

[[ -b /dev/sda ]] → 判断是否为块设备

-c

字符设备文件(如键盘 /dev/tty1)

[[ -c /dev/tty1 ]] → 判断是否为字符设备

-S

套接字文件(如 /var/run/mysql.sock)

[[ -S /var/run/mysql.sock ]] → 判断是否为套接字

(3)权限测试(当前用户是否有对应权限)

运算符

含义

示例

-r

读权限

[[ -r /tmp/file ]] → 当前用户是否能读该文件

-w

写权限

[[ -w /tmp/file ]] → 当前用户是否能写该文件

-x

执行权限(文件)/ 进入权限(目录)

[[ -x /tmp/script.sh ]] → 当前用户是否能执行该脚本

(4)特殊权限测试

运算符

含义

示例

-u

拥有 SUID 权限(执行时继承文件所有者权限)

[[ -u /usr/bin/passwd ]] → 判断 passwd 是否有 SUID

-g

拥有 SGID 权限(执行时继承文件所属组权限)

[[ -g /tmp/dir ]] → 判断目录是否有 SGID

-k

拥有 Sticky 权限(目录中仅所有者可删除自己的文件)

[[ -k /tmp ]] → 判断 /tmp 是否有 Sticky 权限

(5)大小与修改测试

运算符

含义

示例

-s

文件非空(大小 > 0)

[[ -s /tmp/file ]] → 判断文件是否有内容

-N

文件自上次读取后是否被修改过

[[ -N /tmp/file ]] → 判断文件是否被修改

(6)双目测试(两个文件的关系)

运算符

含义

示例

-ef

两个文件是否为同一文件(相同 inode)

[[ /tmp/file1 -ef /tmp/file2 ]] → 判断是否为硬链接

-nt

文件 1 是否比文件 2 新(修改时间)

[[ /tmp/file1 -nt /tmp/file2 ]] → file1 比 file2 新?

-ot

文件 1 是否比文件 2 旧(修改时间)

[[ /tmp/file1 -ot /tmp/file2 ]] → file1 比 file2 旧?

2. 文件测试实战案例

需求:先创建一批测试文件 / 目录,再编写脚本检测它们的属性(存在性、类型、特殊权限等)。

步骤 1:创建测试文件 / 目录
#!/bin/bash

# 脚本名:test.sh

# 创建普通文件

touch /tmp/file1 /tmp/file2

# 创建目录

mkdir /tmp/dir1 /tmp/dir3

# 创建符号链接(指向 dir1)

ln -s /tmp/dir1 /tmp/dir2

# 给 dir3 添加 SGID 权限

chmod g+s /tmp/dir3

echo "测试文件/目录创建完成!"
步骤 2:编写文件测试脚本
#!/bin/bash

# 脚本名:file.sh

# 定义测试文件/目录路径

file1="/tmp/file1"

file2="/tmp/file2"

dir1="/tmp/dir1"

link2="/tmp/dir2"

dir3="/tmp/dir3"

file4="/tmp/file4" # 不存在的文件

# 1. 测试存在性

echo "===== 存在性测试 ====="

[[ -e $file1 ]] && echo "$file1 → 存在" || echo "$file1 → 不存在"

[[ -e $file4 ]] && echo "$file4 → 存在" || echo "$file4 → 不存在"

# 2. 测试文件类型

echo -e "\n===== 类型测试 ====="

[[ -f $file2 ]] && echo "$file2 → 普通文件" || echo "$file2 → 非普通文件"

[[ -d $dir1 ]] && echo "$dir1 → 目录" || echo "$dir1 → 非目录"

[[ -L $link2 ]] && echo "$link2 → 符号链接" || echo "$link2 → 非符号链接"

# 3. 测试特殊权限(SGID)

echo -e "\n===== 特殊权限测试 ====="

[[ -g $dir3 ]] && echo "$dir3 → 拥有 SGID 权限" || echo "$dir3 → 无 SGID 权限"

# 4. 测试权限(当前用户是否有写权限)

echo -e "\n===== 权限测试 ====="

[[ -w $file1 ]] && echo "$file1 → 当前用户有写权限" || echo "$file1 → 当前用户无写权限"
步骤 3:执行与输出结果
# 先创建测试文件

sh test.sh → 测试文件/目录创建完成!

# 执行测试脚本

sh file.sh

输出结果:

===== 存在性测试 =====

/tmp/file1 → 存在

/tmp/file4 → 不存在

===== 类型测试 =====

/tmp/file2 → 普通文件

/tmp/dir1 → 目录

/tmp/dir2 → 链接文件

===== 特殊权限测试 =====

/tmp/dir3 → 拥有 SGID 权限

===== 权限测试 =====

/tmp/file1 → 当前用户有写权限

五、组合测试(多条件判断)

当需要同时判断多个条件时,需使用组合测试运算符(与、或、非),将多个简单条件组合成复杂逻辑。

1. 组合测试运算符

运算符

逻辑关系

说明

示例(判断 $a>10 且 $a<20)

-a

逻辑与(AND)

所有条件都为真,结果才为真

[[ $a -gt 10 -a $a -lt 20 ]]

&&

逻辑与(AND)

Bash 扩展,功能与 -a 一致,优先级更高

[[ $a -gt 10 && $a -lt 20 ]]

-o

逻辑或(OR)

任意一个条件为真,结果就为真

[[ $a -lt 10 -o $a -gt 20 ]]

`

`

逻辑或(OR)

!

逻辑非(NOT)

条件为真时结果为假,条件为假时结果为真

[[ ! -e /tmp/file ]](判断文件不存在)

2. 组合测试实战案例

案例:年龄合法性判断

需求:让用户输入年龄,判断是否在 “18~60” 之间(合法),否则提示 “年龄不合法”。

#!/bin/bash

# 脚本名:age.sh

read -p "请输入你的年龄:" age

# 组合条件:年龄是整数 + 年龄 >=18 + 年龄 <=60

# 步骤1:判断是否为整数

expr $age + 0 > /dev/null 2>&1

if [[ $? -ne 0 ]]; then

echo "错误:年龄必须是整数!"

exit 1

fi

# 步骤2:组合判断年龄范围(18<=age<=60)

if [[ $age -ge 18 && $age -le 60 ]]; then

echo "年龄合法(18~60岁)"

else

echo "年龄不合法(需在18~60岁之间)"

fi
  • 执行示例:
sh age.sh

请输入你的年龄:25 → 年龄合法(18~60岁)

sh age.sh

请输入你的年龄:15 → 年龄不合法(需在18~60岁之间)

sh age.sh

请输入你的年龄:abc → 错误:年龄必须是整数!

六、if 语句(流程控制核心)

if 语句是 Shell 脚本中最基础的流程控制结构,根据条件的真假执行不同的命令块,分为单分支双分支多分支三种形式。

1. 单分支 if 语句(满足条件才执行)

语法格式
if 条件表达式; then

# 条件为真时执行的命令

命令1

命令2

fi # 结束 if 语句(必须闭合)
案例:检查文件是否存在

需求:若 /tmp/file1 存在,输出 “文件已存在”。

#!/bin/bash

# 脚本名:test.sh

file="/tmp/file1"

if [[ -e $file ]]; then

echo "文件已存在:$file"

echo "文件大小:$(du -sh $file)" # 额外输出文件大小

fi

2. 双分支 if 语句(二选一执行)

语法格式
if 条件表达式; then

# 条件为真时执行的命令块

命令1

else

# 条件为假时执行的命令块

命令2

fi

3. 多分支 if 语句(多选一执行)

语法格式
if 条件1; then

# 条件1为真时执行

命令1

elif 条件2; then # else if 的缩写,可多个

# 条件2为真时执行

命令2

elif 条件3; then

# 条件3为真时执行

命令3

else

# 所有条件都为假时执行

命令4

fi
案例:成绩等级判断

需求:根据输入的分数(0~100),判断等级(A:90~100,B:80~89,C:60~79,D:<60)。

#!/bin/bash

# 脚本名:cj.sh

read -p "请输入你的分数(0~100):" score

# 先判断是否为整数且在 0~100 范围内

expr $score + 0 > /dev/null 2>&1

if [[ $? -ne 0 || $score -lt 0 || $score -gt 100 ]]; then

echo "错误:分数必须是 0~100 之间的整数!"

exit 1

fi

# 多分支判断等级

if [[ $score -ge 90 ]]; then

echo "你的等级:A(优秀)"

elif [[ $score -ge 80 ]]; then

echo "你的等级:B(良好)"

elif [[ $score -ge 60 ]]; then

echo "你的等级:C(及格)"

else

echo "你的等级:D(不及格)"

fi
  • 执行示例:
sh cj.sh

请输入你的分数(0~100):85 → 你的等级:B(良好)

sh cj.sh

请输入你的分数(0~100):59 → 你的等级:D(不及格)

sh cj.sh

请输入你的分数(0~100):105 → 错误:分数必须是 0~100 之间的整数!

七、判断逻辑的注意事项

  1. 空格问题:[ ] 或 [[ ]] 前后必须有空格,运算符(如 -eq、==)前后也必须有空格,否则会报语法错误。                                                                                                                            .错误示例:[ $a==$b ](缺少空格);正确示例:[[ $a == $b ]]。
  2. 字符串引号:字符测试时,字符串变量必须加双引号("$str"),避免因字符串为空或含空格导致解析错误。                                                                                                                      错误示例:[[ -z $username ]](空字符串会变成 [[ -z ]],语法错误);正确示例:[[ -z "$username" ]]。
  3. 整数与字符区分:整数测试用 -eq/-gt 等运算符,字符测试用 ==/!= 等运算符,不可混用。  错误示例:[[ "10" -gt "5" ]](字符串用整数运算符,虽可能生效,但不规范);正确示例:[[ 10 -gt 5 ]](整数直接比较)。
  4. 优先级问题:组合测试中,!(非)优先级最高,&&(与)次之,||(或)最低;若有复杂逻辑,建议用 () 包裹(需转义为 \(\) 或用 [[ ]] 自动支持)。                                                    .示例:[[ $age -ge 18 && ($score -ge 60 || $level == "A") ]](先判断分数或等级,再与年龄组合)。
  5. 退出码理解:所有条件测试的结果都通过退出码($?)表示,$?=0 为真,$?!=0 为假;避免直接用 echo $? 输出,应通过 if 或 &&/|| 判断。

总结

Shell 脚本的判断逻辑是流程控制的核心,需掌握以下关键点:

  1. 三类测试:整数测试(比较大小)、字符测试(字符串属性)、文件测试(文件属性),覆盖所有常见判断场景;
  2. 两种格式:推荐使用 [[ 条件 ]] 格式(支持正则和扩展逻辑运算符),避免 [ ] 的兼容性问题;
  3. 三种 if 结构:单分支(满足才执行)、双分支(二选一)、多分支(多选一),根据需求选择合适的结构;
  4. 组合逻辑:用 &&/||/! 实现多条件组合,注意优先级和括号的使用。

通过本文的案例练习,可快速掌握判断逻辑的实际应用,为编写复杂的自动化脚本打下基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值