🔍搜索⌘K

Linux Shell test 命令详解:条件判断的核心工具

概述

在 Shell 脚本中,test 命令是实现 “条件判断” 的核心工具 —— 它能检测变量、字符串、文件等是否满足特定条件,并通过 “退出状态码” 告诉后续逻辑(如 if-then)是否执行。

简单来说,test 命令的核心作用是: “判断一个条件是否成立,成立则返回 0(成功),不成立则返回非 0(失败)”

这种特性让 test 成为 if-then、while、until 等流程控制语句的 “搭档”,是编写逻辑复杂脚本的基础。

一、基础语法:test 命令的两种写法

test 命令有两种等价的使用形式,核心功能完全一致,仅语法风格不同,可根据习惯选择。

1. 标准写法:显式使用 test 关键字

# 格式:test 条件
test condition

# 结合 if-then 使用(最常见场景)
if test condition
then
  # 条件成立时执行的命令
  命令1
  命令2
fi

2. 简化写法:用方括号 [ ] 替代 test

Bash Shell 提供了更简洁的语法,用 [ ] 包裹条件,本质是 test 命令的别名:

# 格式:[ 条件 ](注意:括号与条件间必须有空格!)
[ condition ]

# 结合 if-then 使用
if [ condition ]
then
  # 条件成立时执行的命令
  命令1
  命令2
fi

关键注意点:方括号的空格要求

[ condition ] 中,第一个 [ 后、最后一个 ] 前必须加空格,否则 Shell 会将 [condition] 识别为 “普通命令”,导致语法错误。例如:

  • 正确:[ $var -eq 10 ](括号与条件间有空格)
  • 错误:[$var -eq 10](无空格,会报错 “命令未找到”)

二、无条件测试:test 命令的默认行为

如果 test 命令未指定任何条件(即 test 后无参数,或 [ ] 内为空),它会默认返回 非 0 状态码(条件不成立),可用于检测 “是否漏写条件”。

示例:无参数的 test 命令

#!/bin/bash
# 测试无条件的 test 命令
if test  # 等价于 if [ ]
then
  echo "No expression returns a True"  # 条件成立时执行(不会触发)
else
  echo "No expression returns a False" # 条件不成立时执行(会触发)
fi

执行效果:

No expression returns a False

三、test 命令的三类核心测试场景

test 命令支持三大类条件测试,覆盖 Shell 脚本中 90% 以上的判断需求:数值比较、字符串比较、文件比较。下面逐一详解其语法、示例和注意事项。

1. 数值比较:仅支持整数,不支持浮点数

数值比较用于判断两个整数的大小关系(如 “大于”“等于”“小于”),仅支持整数,浮点数会导致语法错误。

常用数值比较运算符

运算符含义等价数学符号示例(判断 var 是否等于 10)
n1 -eq n2n1 等于 n2==[ $var -eq 10 ]
n1 -ne n2n1 不等于 n2!=[ $var -ne 10 ]
n1 -ge n2n1 大于等于 n2>=[ $var -ge 10 ]
n1 -gt n2n1 大于 n2>[ $var -gt 10 ]
n1 -le n2n1 小于等于 n2<=[ $var -le 10 ]
n1 -lt n2n1 小于 n2<[ $var -lt 10 ]

示例:数值比较的实际使用

#!/bin/bash
value1=10
value2=11

# 测试 value1 是否大于 5
if [ $value1 -gt 5 ]
then
  echo "✅ The test value $value1 is greater than 5."
fi

# 测试 value1 是否等于 value2
if [ $value1 -eq $value2 ]
then
  echo "✅ The values are equal."
else
  echo "❌ The values are different."
fi

执行效果:

✅ The test value 10 is greater than 5.
❌ The values are different.

注意事项

  • 仅支持整数: 若使用浮点数(如 value1=10.5),会报错 “整数表达式预期”;
  • 变量引用加双引号: 建议将变量用双引号包裹(如 [ “$value1” -gt 5 ]),避免变量为空时导致语法错误。

2. 字符串比较:处理文本内容的判断

字符串比较用于判断两个字符串的 “相等性”“大小关系” 或 “是否为空”,是处理用户输入、配置参数的核心场景。

常用字符串比较运算符

运算符含义示例(判断 str 是否等于 “hello”)
str1 = str2str1 与 str2 相等(注意:是单等号)[ “$str” = “hello” ]
str1 != str2str1 与 str2 不相等[ “$str” != “hello” ]
str1 > str2str1 大于 str2(需转义 >,避免被当作重定向)[ “$str1” > “$str2” ]
str1 < str2str1 小于 str2(需转义 <)[ “$str1” < “$str2” ]
-n strstr 长度不为空(非 0)[ -n “$str” ]
-z strstr 长度为空(等于 0)[ -z “$str” ]

示例 1:字符串相等 / 不相等判断

#!/bin/bash
testuser=roger

# 测试字符串相等
if [ "$testuser" = "roger" ]
then
  echo "✅ The testuser variable contains: roger"
else
  echo "❌ The testuser variable contains: $testuser"
fi

# 测试字符串不相等
testuser=rich
if [ "$testuser" != "roger" ]
then
  echo "✅ The testuser variable does NOT contain: roger"
else
  echo "❌ The testuser variable contains: roger"
fi

执行效果:

✅ The testuser variable contains: roger
✅ The testuser variable does NOT contain: roger

示例 2:字符串大小比较(需转义特殊符号)

Shell 中 > 和 < 是 “重定向符号”,用于字符串比较时必须用 \ 转义,否则会被误解析为文件操作。

#!/bin/bash
string1=soccer
string2=zorbfootball

# 错误写法:未转义 >,会被当作重定向,创建 zorbfootball 文件
# if [ $string1 > $string2 ]

# 正确写法:转义 >,实现字符串比较
if [ "$string1" \> "$string2" ]
then
  echo "$string1 is greater than $string2"
else
  echo "$string1 is less than $string2"
fi

执行效果:

soccer is less than zorbfootball

字符串大小比较的规则

字符串比较基于 “字符的 Unicode 编码值” 逐位比较:

  • 小写字母编码:a(97) < b(98) < … < s(115) < … < z(122)
  • 示例中 soccer 的第一个字符 s(115) 小于 zorbfootball 的第一个字符 z(122),因此 soccer < zorbfootball。

示例 3:检测字符串是否为空

-n 和 -z 是检测字符串空值的常用运算符,尤其适合判断 “用户是否输入了内容”:

#!/bin/bash
string1=Soccer   # 非空字符串
string2=''       # 空字符串(显式赋值为空)
# string3 未定义(默认为空)

# 测试 -n:字符串非空
if [ -n "$string1" ]
then
  echo "✅ The string '$string1' is NOT empty"
else
  echo "❌ The string '$string1' IS empty"
fi

# 测试 -z:字符串为空
if [ -z "$string2" ]
then
  echo "✅ The string '$string2' IS empty"
else
  echo "❌ The string '$string2' is NOT empty"
fi

# 测试未定义变量(默认为空)
if [ -z "$string3" ]
then
  echo "✅ The string '$string3' IS empty"
else
  echo "❌ The string '$string3' is NOT empty"
fi

执行效果:

✅ The string 'Soccer' is NOT empty
✅ The string '' IS empty
✅ The string '' IS empty

字符串比较的关键注意点

  • 变量必须加双引号:若变量为空且不加双引号(如 [ $str = “hello” ]),会变成 [ = “hello” ],导致语法错误;加双引号后([ “$str” = “hello” ]),会正确解析为 [ "" = “hello” ];
  • = 是单等号:字符串相等比较用 =(单等号),而非 ==(部分 Shell 支持 ==,但 = 是标准写法,兼容性更好);
  • 转义特殊符号:> 和 < 必须转义为 > 和 <,避免被当作重定向。

3. 文件比较:Linux 文件系统的状态检测

文件比较是 test 命令最强大、最常用的功能 —— 它能检测文件 / 目录的 “存在性”“类型”“权限”“新旧程度” 等,是运维脚本的核心工具(如 “检查日志文件是否存在”“判断脚本是否可执行”)。

常用文件比较运算符

运算符含义示例(判断 file 是否为目录)
-d filefile 存在且是目录[ -d “$file” ]
-e filefile 存在(无论类型是文件还是目录)[ -e “$file” ]
-f filefile 存在且是普通文件(非目录、设备文件等)[ -f “$file” ]
-r filefile 存在且当前用户有读权限[ -r “$file” ]
-w filefile 存在且当前用户有写权限[ -w “$file” ]
-x filefile 存在且当前用户有执行权限[ -x “$file” ]
-s filefile 存在且非空(文件大小 > 0)[ -s “$file” ]
-O filefile 存在且当前用户是文件的所有者[ -O “$file” ]
-G filefile 存在且文件的属组与当前用户的默认属组一致[ -G “$file” ]
file1 -nt file2file1 比 file2 新(修改时间更新)[ “$file1” -nt “$file2” ]
file1 -ot file2file1 比 file2 旧(修改时间更早)[ “$file1” -ot “$file2” ]

下面通过 8 个实战示例,掌握文件比较的核心用法:

示例 1:检查目录是否存在(-d)

在 “切换目录” 或 “向目录写文件” 前,先检查目录是否存在,避免脚本报错:

#!/bin/bash
jump_dir=/home/roger

# 检查目录是否存在
if [ -d "$jump_dir" ]
then
  echo "✅ The $jump_dir directory exists. Entering..."
  cd "$jump_dir" || exit  # 切换目录,失败则退出脚本
  ls -l  # 列出目录内容
else
  echo "❌ The $jump_dir directory does NOT exist."
fi

执行效果(目录不存在时):

❌ The /home/roger directory does NOT exist.

示例 2:检查文件 / 目录是否存在(-e)

-e 是 “通用存在性检测”,无论目标是文件还是目录,只要存在就返回成立:

#!/bin/bash
location=$HOME  # 当前用户的家目录(肯定存在)
file_name="test.log"  # 待检测的文件

# 先检查目录是否存在
if [ -d "$location" ]
then
  echo "✅ Directory $location exists."
  # 再检查文件是否存在
  if [ -e "$location/$file_name" ]
  then
    echo "✅ File $location/$file_name exists. Updating..."
    date >> "$location/$file_name"  # 向文件追加当前时间
  else
    echo "❌ File $location/$file_name does NOT exist. Nothing to do."
  fi
else
  echo "❌ Directory $location does NOT exist. Nothing to do."
fi

执行效果(文件不存在时):

✅ Directory /home/yourname exists.
❌ File /home/yourname/test.log does NOT exist. Nothing to do.

示例 3:检查是否为普通文件(-f)

-e 会同时匹配文件和目录,若需明确 “目标是文件”,需用 -f 检测:

#!/bin/bash
object_name=$HOME  # 家目录(是目录,非文件)

echo "Checking object: $object_name"
if [ -e "$object_name" ]
then
  echo "✅ Object $object_name exists."
  # 进一步判断是文件还是目录
  if [ -f "$object_name" ]
  then
    echo "✅ And it's a regular file."
  else
    echo "✅ And it's a directory."
  fi
else
  echo "❌ Object $object_name does NOT exist."
fi

执行效果:

Checking object: /home/yourname
✅ Object /home/yourname exists.
✅ And it's a directory.

示例 4:检查文件是否可读(-r)

在 “读取文件内容” 前,先检查当前用户是否有读权限,避免 “权限被拒” 错误:

#!/bin/bash
pwfile=/etc/shadow  # 系统密码文件(普通用户无读权限)

echo "Checking read access to $pwfile..."
if [ -f "$pwfile" ]
then
  # 先确认是文件,再检查读权限
  if [ -r "$pwfile" ]
  then
    echo "✅ Read access allowed. Showing last 3 lines..."
    tail -3 "$pwfile"
  else
    echo "❌ Read access denied (normal for regular users)."
  fi
else
  echo "❌ File $pwfile does NOT exist."
fi

执行效果(普通用户执行):

Checking read access to /etc/shadow...
❌ Read access denied (normal for regular users).

示例 5:检查文件是否非空(-s)

-s 用于检测文件是否 “存在且非空”(文件大小 > 0),常用于 “避免删除有内容的文件”:

#!/bin/bash
file_name=$HOME/test.log

echo "Checking if $file_name is empty..."
if [ -f "$file_name" ]
then
  if [ -s "$file_name" ]
then
echo "✅ File $file_name exists and has content. Will NOT delete."
else
echo "❌ File
file_nameexistsbutisempty.Deleting..."rm"
file_name" # 删除空文件
fi
else
echo "❌ File $file_name does NOT exist."
fi

执行效果(文件非空时):

Checking if /home/yourname/test.log is empty...
✅ File /home/yourname/test.log exists and has content. Will NOT delete.

示例 6:检查文件是否可写(-w)

在“向文件写入内容”前,用 -w 检测写权限,避免“无法写入”错误:

#!/bin/bash
item_name=$HOME/test.log

echo "Checking write access to $item_name..."
if [ -f "$item_name" ]
then
  if [ -w "$item_name" ]
  then
    echo "✅ Write access allowed. Appending current time..."
    date +"%Y-%m-%d %H:%M:%S" >> "$item_name"  # 追加时间戳
  else
    echo "❌ Write access denied."
  fi
else
  echo "❌ File $item_name does NOT exist or is not a file."
fi

**执行效果(有写权限时)**:

```plaintext
Checking write access to /home/yourname/test.log...
✅ Write access allowed. Appending current time...

示例 7:检查文件是否可执行(-x)

-x 用于检测脚本或程序是否有 “执行权限”,是 “运行外部程序” 前的必要检查:

#!/bin/bash
script_path=$HOME/scripts/backup.sh  # 待检测的脚本

echo "Checking if $script_path is executable..."
if [ -x "$script_path" ]
then
  echo "✅ Executable. Running the script..."
  "$script_path"  # 执行脚本
else
  echo "❌ Not executable. Try 'chmod +x $script_path' to add permission."
fi

执行效果(无执行权限时):

Checking if /home/yourname/scripts/backup.sh is executable...
❌ Not executable. Try 'chmod +x /home/yourname/scripts/backup.sh' to add permission.

示例 8:比较两个文件的新旧(-nt /-ot)

-nt(newer than)和 -ot(older than)用于比较文件的 “修改时间”,常用于 “判断是否需要更新文件”(如安装包更新):

#!/bin/bash
download_rpm=$HOME/Downloads/games.rpm  # 新下载的安装包
installed_rpm=$HOME/software/games.rpm   # 已安装的旧包

if [ "$download_rpm" -nt "$installed_rpm" ]
then
  echo "✅ $download_rpm is newer. Suggest updating."
else
  echo "❌ $download_rpm is older or same. No need to update."
fi

执行效果(新包更新时):

✅ /home/yourname/Downloads/games.rpm is newer. Suggest updating.

四、复合条件测试:组合多个判断条件

实际脚本中,常需要 “同时满足多个条件” 或 “满足任意一个条件” 才执行命令,此时需用 布尔运算符 组合多个 test 条件。

1. 两种布尔运算符

Shell 支持两种核心布尔逻辑,语法格式如下:

逻辑关系运算符语法格式含义
逻辑与&&[ 条件 1 ] && [ 条件 2 ]两个条件同时成立,整体才成立
逻辑或||[条件 1] || [条件 2]两个条件任意一个成立,整体就成立

2. 示例 1:逻辑与(&&)—— 同时满足两个条件

需求:“目录存在” 且 “文件可写” 时,才向文件写入内容:

#!/bin/bash
dir=$HOME/logs
file=$dir/app.log

# 逻辑与:目录存在 && 文件可写
if [ -d "$dir" ] && [ -w "$file" ]
then
  echo "✅ Directory exists and file is writable. Appending log..."
  echo "[$(date +%H:%M:%S)] App log content" >> "$file"
else
  echo "❌ Either directory does not exist or file is not writable."
fi

执行效果(两个条件都成立时):

✅ Directory exists and file is writable. Appending log...

3. 示例 2:逻辑或(||)—— 满足任意一个条件

需求:“文件不存在” 或 “文件为空” 时,创建新文件并写入初始内容:

#!/bin/bash
file=$HOME/config.ini

# 逻辑或:文件不存在 || 文件为空
if [ ! -e "$file" ] || [ -z "$(cat "$file")" ]  # ! 表示“非”,否定条件
then
  echo "✅ File does not exist or is empty. Creating new file..."
  echo "timeout=30" > "$file"  # 写入初始配置
else
  echo "❌ File exists and has content. Nothing to do."
fi

执行效果(文件不存在时):

✅ File does not exist or is empty. Creating new file...

五、常见问题与避坑指南

使用 test 命令时,新手易因细节忽略导致逻辑错误,以下是高频问题的解决方案:

问题现象根本原因解决方案
方括号语法报错 “命令未找到”[ 后或 ] 前未加空格(如 [$var -eq 10])在括号与条件间加空格,正确格式:[ $var -eq 10 ]
字符串比较时变量为空导致语法错误变量未加双引号(如 [ $str = “hello” ],$str 为空时变成 [ = “hello” ])所有变量引用加双引号,正确格式:[ “$str” = “hello” ]
字符串大小比较时创建空文件未转义 > 或 <(如 [ $str1 > $str2 ],> 被当作重定向)转义特殊符号,正确格式:[ “$str1” > “$str2” ]
数值比较时浮点数报错 “整数表达式预期”test 仅支持整数,不支持浮点数(如 [ 10.5 -gt 5 ])若需处理浮点数,改用 bc 命令计算(如 if (($(echo”10.5> 5” | bc) )); then …`)
文件比较时路径含空格导致错误路径变量未加双引号(如 [ -f $HOME/my file.txt ],被拆分为 [ -f /home/yourname/my file.txt ])路径变量加双引号,正确格式:[ -f “$HOME/my file.txt” ]

六、总结:test 命令的核心要点

  1. 本质定位:Shell 条件判断的 “基石”,通过退出状态码(0 成功 / 非 0 失败)告知条件是否成立;
  2. 两种语法:test 条件 和 [ 条件 ] 等价,后者更简洁,但需注意括号与条件间的空格;
  3. 三大场景:
    • 数值比较:仅支持整数,用 -eq/-gt 等运算符;
    • 字符串比较:需加双引号,>/< 需转义,-n/-z 检测空值;
    • 文件比较:最常用,覆盖存在性、权限、新旧等检测,是运维脚本核心;
  4. 复合条件:用 &&(与)、||(或)组合多个条件,实现复杂逻辑;
  5. 避坑关键:变量加双引号、括号加空格、转义特殊符号、不处理浮点数。

test 命令是 Shell 脚本的 “逻辑骨架”,掌握它后,无论是 if-then 的分支判断,还是 while/until 的循环控制,都能轻松实现。建议结合实际场景多练习(如 “检查日志文件是否存在且可读”“判断用户输入是否为空”),逐步形成条件判断的思维习惯。