Shell 脚本条件测试

Shell 脚本条件测试

6.1 条件测试简介

在 Shell 脚本中,我们经常需要做条件判断,根据不同的测试结果执行不同的操作。这就像是在问问题,然后根据"是"或"否"来决定下一步做什么。

执行条件测试后:

  • 返回 0 表示"真"(条件成立)
  • 返回非0 表示"假"(条件不成立)

条件测试的五种语法格式

  1. test <表达式>
    test 命令后需要加空格再写表达式
  2. [ <表达式> ]推荐使用 👍)
    test 等效,方括号内两端需要有空格
  3. [[ <表达式> ]]
    功能更强的扩展版本,两端也需要空格
  4. (( <表达式> ))
    主要用于数值计算和比较,两端不需要空格
  5. 直接使用命令
    根据命令执行的成功(返回0)或失败(返回非0)来判断

6.1.1 test 条件测试示例

test 命令用于检查文件类型、比较值等。可以通过 help test 查看所有选项。

示例 1:检查文件是否存在

bash

复制代码
[azurewhisky@shell ~]$ test -f file && echo true || echo false
  • 如果 file 存在(真),输出 true
  • 如果 file 不存在(假),输出 false
  • -f 测试是否为普通文件
  • && 表示"前一个命令成功就执行下一个"
  • || 表示"前一个命令失败就执行下一个"

也可以分开写:

bash

复制代码
[azurewhisky@shell ~]$ test -f file && echo true  # 存在才输出
[azurewhisky@shell ~]$ test -f file || echo false # 不存在才输出

示例 2:检查变量是否为空

bash

复制代码
[azurewhisky@shell ~]$ unset string        # 删除变量
[azurewhisky@shell ~]$ test -z "$string" && echo null string || echo $string
null string

[azurewhisky@shell ~]$ string="hello world"
[azurewhisky@shell ~]$ test -z "$string" && echo null string || echo $string
hello world
  • -z 判断字符串长度是否为 0(空)
  • 注意:变量建议用双引号括起来,防止空变量导致语法错误

6.1.2 [] 条件测试示例

[]test 功能完全相同,只是写法不同。

示例:检查文件是否存在

bash

复制代码
[azurewhisky@shell ~]$ [ -f file ] && echo true || echo false
  • 方括号 [ ] 内部两端必须有空格
  • 逻辑操作符 &&|| 两端加空格更清晰(可选但建议)

6.1.3 [[]] 条件测试示例

[[]] 是增强版测试命令,支持更强大的模式匹配。

示例:检查文件是否存在

bash

复制代码
[azurewhisky@shell ~]$ [[ -f file ]] && echo true || echo false
  • 双括号 [[ ]] 内部两端也需要空格

提示test[][[]] 功能相似,选择一种你喜欢的即可(推荐 [])。


6.2 文件判断表达式

常用的文件测试选项:

选项 全拼 说明
-d directory 存在且为目录则为真
-f file 存在且为普通文件则为真
-e exist 存在则为真(不区分文件或目录)
-r read 存在且可读则为真
-s size 存在且大小非0则为真
-w write 存在且可写则为真
-x executable 存在且可执行则为真
-L link 存在且为链接文件则为真
-nt newer than 文件1比文件2新则为真(按修改时间)
-ot older than 文件1比文件2旧则为真(按修改时间)

示例:

bash

复制代码
[azurewhisky@shell ~]$ data_path=/tmp/azurewhisky
[azurewhisky@shell ~]$ mkdir ${data_path}
[azurewhisky@shell ~]$ [ -d ${data_path} ] && echo "${data_path} exists"
/tmp/azurewhisky exists

[azurewhisky@shell ~]$ rmdir ${data_path}
[azurewhisky@shell ~]$ [ -d ${data_path} ] || echo "${data_path} does not exist"
/tmp/azurewhisky does not exist

# 检查是否可读 /etc/shadow(通常需要root权限)
[azurewhisky@shell ~]$ [ -r /etc/shadow ] && cat /etc/shadow || echo "Cannot read shadow file"
Cannot read shadow file

# 如果 ~/.bashrc 可写,则追加别名
[azurewhisky@shell ~]$ [ -w ~/.bashrc ] && echo "alias pa='ps axu'" >> ~/.bashrc
[azurewhisky@shell ~]$ tail -1 ~/.bashrc
alias pa='ps axu'

多条命令的条件执行

如果条件成立后要执行多条命令,可以用 {} 组合:

bash

复制代码
[ 条件 ] && {
  命令1
  命令2
  命令3
}

示例:

bash

复制代码
[azurewhisky@shell ~]$ [ -w ~/.bashrc ] && {
> echo "alias sa='ssh root@servera'" >> ~/.bashrc
> echo "alias sb='ssh root@serverb'" >> ~/.bashrc
> echo "alias sc='ssh root@serverc'" >> ~/.bashrc
> }

[azurewhisky@shell ~]$ tail -3 ~/.bashrc
alias sa='ssh root@servera'
alias sb='ssh root@serverb'
alias sc='ssh root@serverc'

# 一行写多条命令(用分号分隔)
[azurewhisky@shell ~]$ [ -r /etc/passwd ] && { echo ha; echo ha; echo ha; }
ha
ha
ha

6.3 字符串判断表达式

常用字符串测试操作符:

表达式 说明
-n "字符串" 长度不为0则为真(非空)
-z "字符串" 长度为0则为真(空)
"串1" = "串2" 字符串相等则为真
"串1" != "串2" 字符串不相等则为真

重要提示:

  • 字符串一定要用双引号括起来,避免空变量导致语法错误
  • 比较操作符(如 =两端必须有空格

示例 1:检查空字符串

bash

复制代码
[azurewhisky@shell ~]$ unset string
[azurewhisky@shell ~]$ [ -z "$string" ] && echo "null string" || echo "$string"
null string

[azurewhisky@shell ~]$ string="hello world"
[azurewhisky@shell ~]$ [ -z "$string" ] && echo "null string" || echo "$string"
hello world

示例 2:检查非空字符串

bash

复制代码
[azurewhisky@shell ~]$ unset string
[azurewhisky@shell ~]$ [ -n "$string" ] && echo "$string" || echo "null string"
null string

[azurewhisky@shell ~]$ string="hello world"
[azurewhisky@shell ~]$ [ -n "$string" ] && echo "$string" || echo "null string"
hello world

示例 3:字符串比较

bash

复制代码
[azurewhisky@shell ~]$ string="hi"
[azurewhisky@shell ~]$ [ "$string" = "hi" ] && echo hi
hi
[azurewhisky@shell ~]$ [ "$string" = "ha" ] && echo ha  # 无输出

[azurewhisky@shell ~]$ [ "$string" != "hi" ] && echo "not hi"  # 无输出
[azurewhisky@shell ~]$ [ "$string" != "ha" ] && echo "not ha"
not ha

实际应用案例

查看系统脚本中的条件判断:

bash

复制代码
[azurewhisky@shell ~]$ sed -n '30,31p' /etc/init.d/network
# Check that networking is up.
[ "${NETWORKING}" = "no" ] && exit 6

6.3.3 [[]] 中的模式匹配 =~

[[ ]] 支持使用 =~ 进行正则表达式匹配:

bash

复制代码
[[ "$str" =~ pattern ]]

重要: =~ 右边的模式不要用引号,否则会被当作普通字符串而不是正则表达式。

示例:

bash

复制代码
# 检查变量是否包含数字
[azurewhisky@shell ~]$ str=123abc
[azurewhisky@shell ~]$ [[ "$str" =~ [0-9]+ ]] && echo "Contains numbers" || echo "No numbers"
Contains numbers

[azurewhisky@shell ~]$ str=abcdef
[azurewhisky@shell ~]$ [[ "$str" =~ [0-9]+ ]] && echo "Contains numbers" || echo "No numbers"
No numbers

# 检查变量是否全是数字
[azurewhisky@shell ~]$ str=123
[azurewhisky@shell ~]$ [[ "$str" =~ ^[0-9]+$ ]] && echo "All numbers" || echo "Not all numbers"
All numbers

# 错误示例:加引号后正则会失效
[azurewhisky@shell ~]$ str=123
[azurewhisky@shell ~]$ [[ "$str" =~ "[0-9]+" ]] && echo true || echo false 
false

6.4 整数比较操作符

两种风格的整数比较操作符:

在 [] 和 test 中 在 [[]] 和 (()) 中 说明
-eq === 等于(equal)
-ne != 不等于(not equal)
-gt > 大于(greater than)
-ge >= 大于等于(greater equal)
-lt < 小于(less than)
-le <= 小于等于(less equal)

特别注意:

  • [] 中使用 >< 时需要转义(如 \>),否则可能被解释为重定向
  • 整数比较时,变量可以不加引号,但加上也不错

示例 1:使用 [] 比较

bash

复制代码
[azurewhisky@shell ~]$ [ 2 -lt 3 ] && echo true || echo false
true
[azurewhisky@shell ~]$ [ 2 -gt 3 ] && echo true || echo false
false

示例 2:常见错误

bash

复制代码
# 错误:> 不被转义时实际上是重定向,创建了名为 3 的文件!
[azurewhisky@shell ~]$ [ 2 > 3 ] && echo true
true

# 正确:需要转义 >
[azurewhisky@shell ~]$ [ 2 \> 3 ] && echo true || echo false
false

示例 3:使用 [[]] 和 (()) 比较

bash

复制代码
[azurewhisky@shell ~]$ a=98;b=99
[azurewhisky@shell ~]$ [[ $a = $b ]] && echo true || echo false
false

[azurewhisky@shell ~]$ (( a >= b )) && echo true || echo false
false
[azurewhisky@shell ~]$ (( a <= b )) && echo true || echo false
true

小结:

  • [] 中用 -eq, -ne 等比较整数
  • [[]](()) 中用 ==, !=, >, < 等比较整数
  • [] 中使用 >< 需要转义

6.5 逻辑操作符

表达式内的逻辑操作符

在 [] 和 test 中 在 [[]] 和 (()) 中 说明
-a && 与(and)
-o ` ` 或(or)
! ! 非(not)

表达式外的逻辑操作符(连接命令)

  • &&:左边成功才执行右边
  • ||:左边失败才执行右边

示例:

bash

复制代码
# 检查文件是否存在且可读
[azurewhisky@shell ~]$ file=/etc/passwd
[azurewhisky@shell ~]$ [ -f "$file" -a -r "$file" ] && head -1 "$file"
root:x:0:0:root:/root:/bin/bash

# 使用 && 连接两个测试条件
[azurewhisky@shell ~]$ num=10
[azurewhisky@shell ~]$ [ "$num" -lt 20 -o "$num" -gt 1 ] && echo "$num is between 1 and 20"
10 is between 1 and 20

# 使用 ! 取反
[azurewhisky@shell ~]$ [ ! 6 -eq 5 ] && echo "6 != 5"
6 != 5

实际应用案例

bash

复制代码
# 如果目录不存在则创建
[azurewhisky@shell ~]$ data_path=/tmp/azurewhisky
[azurewhisky@shell ~]$ [ -d "$data_path" ] || mkdir "$data_path"
[azurewhisky@shell ~]$ ls -d "$data_path"
/tmp/azurewhisky

6.6 四种测试方法对比总结

特性说明 [] test [[]] (())
边界是否需要空格 需要 需要 需要 不需要
逻辑操作符 !、-a、-o !、-a、-o !、&&、|| !、&&、||
整数比较 -eq、-ne、-gt等 -eq、-ne、-gt等 -eq、-ne、-gt等 ==、!=、>、<等
字符串比较 =、==、!= =、==、!= =、==、!= ==、!=
通配符匹配 不支持 不支持 支持(=~) 不支持

建议:

  • 日常使用 [] 足够多数情况
  • 需要模式匹配时用 [[]]
  • 数值计算用 (())
  • 保持代码风格一致最重要

希望这份更轻松易懂的笔记能帮助你更好地学习和复习 Shell 条件测试!如有问题,欢迎随时提问。