条件测试

条件测试常用语法

在 bash 编程里,条件测试常用的语法如下:

  • 语法1:test <判断表达式>,test命令和"<判断表达式>"之间至少有一个空格。
  • 语法2:[ <判断表达式> ],和test命令的用法相同,这是推荐方法。[]的边界和内容之间至少有一个空格。
  • 语法3:[[ <判断表达式> ]],是比test和[]更新的语法格式。[[]]的边界和内容之间至少有一个空格。
  • 语法4:(( <判断表达式> )),一般用于 if 语句。(())(双小括号)两端不需要有空格。
  • 语法5:comand,命令的返回值确定表达式的真值或假值。

条件测试常用于判断以下内容:

  • 字符串
  • 数值
  • 文件、进程、服务、用户等

test

帮助信息

[root@CentOS ~ 10:06:17]# help test
test: test [expr]
    Evaluate conditional expression.

    Exits with a status of 0 (true) or 1 (false) depending on
    the evaluation of EXPR.  Expressions may be unary or binary.  Unary
    expressions are often used to examine the status of a file.  There
    are string operators and numeric comparison operators as well.

    The behavior of test depends on the number of arguments.  Read the
    bash manual page for the complete specification.

    File operators:

      -a FILE        True if file exists.
      -b FILE        True if file is block special.
      -c FILE        True if file is character special.
      -d FILE        True if file is a directory.
      -e FILE        True if file exists.
      -f FILE        True if file exists and is a regular file.
      -g FILE        True if file is set-group-id.
      -h FILE        True if file is a symbolic link.
      -L FILE        True if file is a symbolic link.
      -k FILE        True if file has its `sticky' bit set.
      -p FILE        True if file is a named pipe.
      -r FILE        True if file is readable by you.
      -s FILE        True if file exists and is not empty.
      -S FILE        True if file is a socket.
      -t FD          True if FD is opened on a terminal.
      -u FILE        True if the file is set-user-id.
      -w FILE        True if the file is writable by you.
      -x FILE        True if the file is executable by you.
      -O FILE        True if the file is effectively owned by you.
      -G FILE        True if the file is effectively owned by your group.
      -N FILE        True if the file has been modified since it was last read.

      FILE1 -nt FILE2  True if file1 is newer than file2 (according to
                       modification date).

      FILE1 -ot FILE2  True if file1 is older than file2.

      FILE1 -ef FILE2  True if file1 is a hard link to file2.

    String operators:

      -z STRING      True if string is empty.

      -n STRING
         STRING      True if string is not empty.

      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.

    Other operators:

      -o OPTION      True if the shell option OPTION is enabled.
      -v VAR     True if the shell variable VAR is set
      ! EXPR         True if expr is false.
      EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
      EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.

      arg1 OP arg2   Arithmetic tests.  OP is one of -eq, -ne,
                     -lt, -le, -gt, or -ge.

    Arithmetic binary operators return true if ARG1 is equal, not-equal,
    less-than, less-than-or-equal, greater-than, or greater-than-or-equal
    than ARG2.

    Exit Status:
    Returns success if EXPR evaluates to true; fails if EXPR evaluates to
    false or an invalid argument is given.

判断文件

判断文件是否存在

[root@CentOS ~ 09:34:38]# file=~/home/tz/tz.txt
# 如果文件存在,则显示文件存在
[root@CentOS ~ 09:39:49]# test -a $file && echo "$file is exist." || echo "$file is not exist."
# 输出内容如下
/root/home/tz/tz.txt is exist.

[root@CentOS ~ 09:40:39]# file=~/home/tz/tz1.txt
# 如果文件不存在,则显示文件不存在
[root@CentOS ~ 09:41:11]# test -a $file && echo "$file is exist." || echo "$file is not exist."
# 输出内容如下
/etc/fstab-abc is not exist.

判断目录是否存在:

  • 如果不存在,则创建目录。
  • 如果存在,则提示目录存在。
[root@CentOS ~ 09:42:37]# dir_path=~/home/tz/webapp
[root@CentOS ~ 09:43:06]# ls ${dir_path} 
ls: 无法访问/root/home/tz/webapp: 没有那个文件或目录

# 执行完成后,创建了目录
[root@CentOS ~ 09:43:13]# test -d ${dir_path} && echo "${dir_path} is exist." || mkdir  ${dir_path}

# 提示目录已经存在
[root@CentOS ~ 09:43:21]# test -d ${dir_path} && echo "${dir_path} is exist." || mkdir  ${dir_path}
/root/home/tz/webapp is exist.

其他示例

# 如果对文件具有读取权限,则显示文件内容
[root@CentOS ~ 09:47:53]$ ls -ld /etc/fstab /etc/shadow
-rw-r--r--. 1 root root 541 Apr  3 14:10 /etc/fstab
----------. 1 root root 690 Apr  3 14:15 /etc/shadow

# 无读取权限,输出内容为空
[root@CentOS ~ 09:48:10]$ test -r /etc/shadow && tail -5 /etc/shadow 

# 有读取权限,输出内容
[root@CentOS ~ 09:48:05]$ test -r /etc/fstab && tail -5 /etc/fstab 
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=8c0568e1-c35f-49d2-9f4c-e63e76dc1473 /boot                   xfs     defaults        0 0
/dev/mapper/centos-home /home                   xfs     defaults        0 0
/dev/mapper/centos-swap swap                    swap    defaults        0 0

思考:对于文件/tmp/test.log,如果有写入权限,则写入"hello world."

[root@CentOS ~ 10:04:18]$ touch /tmp/test.log
[root@CentOS ~ 10:04:39]$ test -w /tmp/test.log && echo "hello world." > /tmp/test.log
[root@CentOS ~ 10:04:46]$ cat /tmp/test.log
hello world.

判断字符串

  • -z,字符串为空,则为true
  • -n,字符串非空,则为true
# 测试变量是否定义
[root@CentOS ~ 10:06:17]# test -z "$testvar" && echo 'testvar is not defined.' || echo "testvar is $testvar."
testvar is not defined.

[root@CentOS ~ 10:13:16]# testvar=hi
[root@CentOS ~ 10:13:18]# test -z "$testvar" && echo 'testvar is not defined.' || echo "testvar is $testvar."
# 输出变量值
testvar is hi.


# 取消变量定义
[root@CentOS ~ 10:13:24]# unset testvar
[root@CentOS ~ 10:13:41]# test -n "$testvar" && echo "testvar is $testvar." || \
> testvar=zhangsan

# 再次打印,显示变量值
[root@CentOS ~ 10:14:13]# test -n "$testvar" && echo "testvar is $testvar." || testvar=zhangsan
testvar is zhangsan.
  • STRING1 = STRING2,True if the strings are equal.
  • STRING1 != STRING2,True if the strings are not equal.
# 检查当前运行的用户
# 如果不是root用户,则提示:请以root身份运行
# 如果是root用户,则执行创建用户zhangsan

# 普通用户运行,则提示:请以root身份运行
[tz@CentOS root 10:33:18]$ test "$USER" = "root" && useradd zhangsan || echo "Please run as root."
Please run as root.

# root用户运行,创建用户成功
[root@CentOS ~ 10:34:31]# test "$USER" = "root" && useradd zhangsan || echo "Please run as root."
[root@CentOS ~ 10:35:06]# id zhangsan
uid=1001(zhangsan) gid=1001(zhangsan)=1001(zhangsan)

# 等效于以下命令
[root@CentOS ~ 10:35:08]# test "$USER" != "root" && echo "Please run as root." || useradd zhangsan
Please run as root.

判断数值

arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne, -lt, -le, -gt, or -ge.

# 检查当前运行的用户
# 如果不是root用户,则提示:请以root身份运行
# 如果是root用户,则执行删除用户zhangsan

# 普通用户运行,则提示:请以root身份运行
[tz@CentOS root 10:35:45]$ test $UID -eq 0 && userdel -r zhangsan || echo "Please run as root."
Please run as root.

# root用户运行,删除用户成功
[root@CentOS ~ 10:36:29]# test $UID -eq 0 && userdel -r zhangsan || echo "Please run as root."
[root@CentOS ~ 10:36:34]# id zhangsan
id: zhangsan: no such user

多条件测试

  • ! EXPR True if expr is false.
  • EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
  • EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.
[root@CentOS ~ 11:25:06]# file=/tmp/test.log

# 逻辑非:提交取反满足
[root@CentOS ~ 11:38:33]# [ ! -a $file ] && touch $file && echo "create file success."
create file success.
[root@CentOS ~ 11:39:08]# ls $file
/tmp/test.log

# 逻辑与:两个条件同时满足
[root@CentOS ~ 11:39:24]# [ -w $file -a -a $file ] && date > $file
[root@CentOS ~ 11:39:36]# cat $file
2026年 04月 13日 星期一 11:39:36 CST

# 逻辑或:两个条件任一满足
[root@CentOS ~ 11:39:42]# file1=/etc/yum.conf
[root@CentOS ~ 11:40:44]# file2=/etc/yum.repos.d/CentOS-Base.repo
[root@CentOS ~ 11:40:50]# [ -a $file1 -o -a $file2 ] && echo 'yum repository is exist.'
yum repository is exist.

[[ ]] 条件测试

大部分等效于 [],多条件判断有些区别。

  • ! EXPR True if expr is false.
  • EXPR1 && EXPR2 True if both expr1 AND expr2 are true.
  • EXPR1 || EXPR2 True if either expr1 OR expr2 is true.
[root@CentOS ~ 11:40:56]# file=/tmp/test.log

# 逻辑非:提交取反满足
[root@CentOS ~ 11:42:26]# [[ ! -a $file ]] && touch $file && echo "create file success."
create file success.
[root@CentOS ~ 11:42:28]# ls $file
/tmp/test.log

# 逻辑与:两个条件同时满足
[root@CentOS ~ 11:43:02]# [[ -w $file && -a $file ]] && date > $file
[root@CentOS ~ 11:43:13]# cat $file
2026年 04月 13日 星期一 11:43:13 CST

# 逻辑或:两个条件任一满足
[root@CentOS ~ 11:43:18]# file1=/etc/yum.conf
[root@CentOS ~ 11:43:32]# file2=/etc/yum.repos.d/CentOS-Base.repo
[root@CentOS ~ 11:43:42]# [[ -a $file1 || -a $file2 ]] && echo 'yum repository is exist.'
yum repository is exist.

(()) 条件测试

主要用于数值比较。

# 检查当前运行的用户
# 如果不是root用户,则提示:请以root身份运行
# 如果是root用户,则执行删除用户zhangsan

# 普通用户运行,则提示:请以root身份运行
[tz@CentOS root 11:44:16]$ (($UID == 0)) && userdel -r zhangsan || echo "Please run as root."
Please run as root.
# root用户运行,删除用户成功
[root@CentOS ~ 11:45:16]# (($UID == 0)) && userdel -r zhangsan || echo "Please run as root."
[root@CentOS ~ 11:45:17]# id zhangsan
id: zhangsan: no such user

判断表达式总结

判断表达式符号 [] test [[]] (())
边界是否需要空格 需要 需要 需要 不需要
逻辑操作符 !、-a、-o !、 -a、 -o !、&&、|| !、&&、||
整数比较操作符 -eq、-ne、-gt、-ge、-lt、-le -eq、-ne、-gt、-ge、-lt、-le -eq、-ne、-gt、-ge、-lt、-le ==、!=、>、>=、<、<=
字符串比较操作符 =、== 、!= =、== 、!= =、== 、!= = 、!=
是否支持通配符匹配 不支持 不支持 支持(=~) 不支持

IF 语句

语法

单分支语法

# 单分支
if 条件判断;then
  command
fi

if 条件判断
then
  command
fi

条件判断 && command

双分支语法

# 单分支
if 条件判断;then
  command1
else
  command2
fi

条件判断 && command1 || command2

多分支语法

# 单分支
if 条件1判断;then
  command1
elif 条件2判断;then
  command2
else
  command3
fi

实践

示例1:单分支

需求:如果sshd服务正常运行,则提示服务正在运行。

开发脚本if_sshd_1.sh ,内容如下:

[root@centos7 bin 13:53:41]# vim if_ssh_1.sh
#!/bin/bash
status="$(systemctl is-active sshd)"
if [ "$status" == "active" ];then
  echo sshd is running.
fi

或者

#!/bin/bash
systemctl is-active sshd &>/dev/null
if (($?==0));then
  echo sshd is running.
fi

运行结果:

[root@CentOS bin 13:46:42]# systemctl start sshd
[root@CentOS bin 13:46:46]# bash if_sshd_1.sh 
sshd is running.

示例2:双分支

需求:

  • 如果sshd服务正常运行,则提示服务正在运行
  • 提示服务未运行,并启动服务,启动后提示服务正常运行。

开发脚本if_sshd_2.sh ,内容如下:

[root@centos7 bin 13:43:41]# vim if_ssh_2.sh
#!/bin/bash
status="$(systemctl is-active sshd)"
if [ "$status" == "active" ];then
  echo sshd is running.
else
  systemctl start sshd && echo "Start sshd success."
fi

运行结果:

[root@CentOS bin 13:50:44]# systemctl stop sshd
[root@CentOS bin 13:51:29]# bash if_sshd_2.sh
Start sshd success.
[root@CentOS bin 13:51:33]# bash if_sshd_2.sh
sshd is running.

示例3:多分支

需求:开发if_sshd_3.sh脚本。

  • 脚本使用方法:“Usage:$0 start|stop|status|restart|reload”
  • 如果参数数量个数不是1个,则输出脚本使用方法。
  • 如果$1是start,则执行’systemctl start sshd’
  • 如果$1是stop,则执行’systemctl stop sshd’
  • 如果$1是status,则执行’systemctl status sshd’
  • 如果$1是restart,则执行’systemctl restart sshd’
  • 如果$1是reload,则执行’systemctl reload sshd’
  • 如果$1是其他子命令,则输出脚本使用方法。

开发脚本if_sshd_3.sh ,内容如下:

[root@CentOS bin 14:12:36]# vim if_sshd_3.sh
#!/bin/bash

service_name=sshd

if (($#!=1));then
  echo "Usage:$0 start|stop|status|restart|reload"
  exit
fi

if [ "$1" == "start" ];then
  systemctl start ${service_name}
elif [ "$1" == "stop" ];then
  systemctl stop ${service_name}
elif [ "$1" == "status" ];then
  systemctl status ${service_name}
elif [ "$1" == "restart" ];then
  systemctl restart ${service_name}
elif [ "$1" == "reload" ];then
  systemctl reload ${service_name}
else
  echo "Usage:$0 start|stop|status|restart|reload"
fi

运行结果:

[root@CentOS bin 14:15:42]# chmod +x if_sshd_3.sh

# 缺乏参数
[root@CentOS bin 14:15:55]# if_sshd_3.sh 
Usage:/usr/bin/if_sshd_3.sh start|stop|status|restart|reload

# 只能传递1个参数
[root@CentOS bin 14:16:03]# if_sshd_3.sh start stop
Usage:/usr/bin/if_sshd_3.sh start|stop|status|restart|reload

# 传递正常参数
[root@CentOS bin 14:17:00]# if_sshd_3.sh status
● sshd.service - OpenSSH server daemon
   Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
   Active: active (running) since 一 2026-04-13 13:54:15 CST; 22min ago
     Docs: man:sshd(8)
           man:sshd_config(5)
 Main PID: 31661 (sshd)
    Tasks: 1
   CGroup: /system.slice/sshd.service
           └─31661 /usr/sbin/sshd -D

413 13:54:15 CentOS.tz.cloud systemd[1]: Starting OpenSSH server daemon...
413 13:54:15 CentOS.tz.cloud sshd[31661]: Server listening on 0.0.0.0 port 22.
413 13:54:15 CentOS.tz.cloud sshd[31661]: Server listening on :: port 22.
413 13:54:15 CentOS.tz.cloud systemd[1]: Started OpenSSH server daemon.
Hint: Some lines were ellipsized, use -l to show in full.

# 传递不存在的参数
[root@CentOS bin 14:17:09]# if_sshd_3.sh haha
Usage:/usr/bin/if_sshd_3.sh start|stop|status|restart|reload

示例4:综合练习

开发脚本servicectl,模拟systemctl 控制服务。

不带注释

#!/bin/bash

service_name="$2"
action="$1"

if (($#!=2));then
  echo "Usage:$0 start|stop|status|restart|reload ${service_name}"
  exit
fi

if [ "$action" == "start" -o "$action" == "stop" -o "$action" == "status"  -o "$action" == "restart" -o "$action" == "reload" ];then
  systemctl $action ${service_name}
else
  echo "Usage:$0 start|stop|status|restart|reload"
fi

带注释

#!/bin/bash
# 功能:通用 Linux 服务管理脚本
# 用法:./脚本名 动作 服务名
# 示例:./servicectl start nginx

# ====================== 变量定义 ======================
# 第一个参数:要执行的动作(start/stop/restart/status/reload)
action="$1"

# 第二个参数:要操作的服务名称(nginx、sshd、mysql 等)
service_name="$2"

# ====================== 参数个数校验 ======================
# 判断参数是否为 2 个,不是则提示用法并退出
if (($# != 2)); then
  echo "用法:$0 start|stop|status|restart|reload 服务名"
  exit 1
fi

# ====================== 动作合法性判断 ======================
# 判断用户输入的动作是否是合法的系统服务命令
if [ "$action" == "start" -o "$action" == "stop" -o "$action" == "status" -o \
     "$action" == "restart" -o "$action" == "reload" ]; then

  # 执行 systemctl 命令管理服务
  systemctl $action ${service_name}
else
  # 动作不合法,提示正确用法
  echo "错误:不支持的操作!"
  echo "用法:$0 start|stop|status|restart|reload 服务名"
  exit 1
fi

FOR 语句

语法

shell 自带语法

for 变量名 in 清单
do
  command
done

C语言格式语法

for ((num=1;num<=10;num++))
do
  echo $num
done

执行效果如下

1
2
3
4
5
6
7
8
9
10

实践

示例1:计算1+2+…+9+10的和

[root@CentOS bin 15:14:26]# vim for_1_sum.sh

#!/bin/bash
sum=0
for num in {1..10}
do
  sum=$[ sum + num ]
done
echo "1+2+..+9+10=$sum"

示例2:批量重命名文件

具体需求:将某个目录下文件命中字符串snap替换为pic。

模拟:

[root@CentOS bin 15:17:24]# mkdir Pictures
[root@CentOS bin 15:48:51]# touch Pictures/snap-{01..10}.jpg

for_2_rename.sh 代码如下:

[root@centos7 bin 15:37:16]# vim for_2_rename.sh
#!/bin/bash
for file in Pictures/snap*
do
  file_old_name=$file
  file_new_name=${file_old_name/snap/pic}
  mv ${file_old_name} ${file_new_name}
done

执行效果如下:

[root@CentOS bin 15:51:06]# bash for_2_rename.sh
[root@CentOS bin 15:51:18]# ls Pictures/
pic-01.jpg  pic-03.jpg  pic-05.jpg  pic-07.jpg  pic-09.jpg
pic-02.jpg  pic-04.jpg  pic-06.jpg  pic-08.jpg  pic-10.jpg

思考:将某个目录下所有文件备份到/backup目录,文件名添加.bak后缀。

示例3:批量创建用户

公司新入职一批员工,需要为这些员工创建账号。

  1. 员工姓名清单保存在staff.txt中,每行一个。
  2. 为每个员工创建一个初始密码,初始密码是8位随机值,要求登录后必须修改密码。
  3. 创建的结果要保存到users_info.conf中,格式为username: password。

准备员工姓名清单:

[root@CentOS bin 16:19:12]# vim staff.txt
jack
tom
zhangsan
laowang

脚本内容如下:

#!/bin/bash

staff_name_file=staff.txt
staff_info_file=users_info.conf

if [ -a ${staff_name_file} -a -r ${staff_name_file} ];then
  for staff in $(cat ${staff_name_file})
  do
    useradd $staff
    password=$(date +%N | md5sum | head -c10)
    echo $password | passwd --stdin $staff &>/dev/null
    echo "$staff: $password" >> ${staff_info_file}
  done
else
  echo "${staff_name_file} is not exist."
fi

执行效果如下:

[root@CentOS bin 16:29:14]# bash for_3_users.sh 
[root@CentOS bin 16:29:21]# cat users_info.conf 
jack: bce575ef4b
tom: 6db89d5834
zhangsan: ee4b67c847
laowang: e2e2136347

生成随机值常见方法:

  1. 利用时间生成纳秒级别值:date +%N
[root@centos7 bin 16:04:25]# date +%N
456812617
  1. mktemp命令创建一个临时目录,目录名是随机值。
[root@centos7 bin 16:05:14]# echo $(mktemp)
/tmp/tmp.ncZkKK9TYD
  1. 利用环境变量RANDOM生成0~32767随机值。

总结:$() $[] ${}

  • $() :命令替换
  • $[]:数值计算
  • ${}:变量替换

while/until 语句

条件满足或者不满足,一直运行。

语法

while

条件满足,一直运行。

while 条件判断
do
  command
done

until

条件不满足,一直运行。满足条件,则终止运行。

until 条件判断
do
  command
done

实践

示例1:挣1个小目标

while_1_target.sh 脚本内容如下:

#!/bin/bash
target=100000000
money=100
while ((money<target))
do
   echo -n "I'm working hard ... "
   sleep 1
   money=$[ money+10000000 ]
   echo $money
done

执行结果:

[root@centos7 bin 16:49:08]# bash while_1_target.sh 
I'm working hard ... 10000100
I'm working hard ... 20000100
I'm working hard ... 30000100
I'm working hard ... 40000100
I'm working hard ... 50000100
I'm working hard ... 60000100
I'm working hard ... 70000100
I'm working hard ... 80000100
I'm working hard ... 90000100
I'm working hard ... 100000100

示例 2:监控 sshd 服务

开发脚本monitor_sshd.sh 实时监控sshd服务,实现以下功能:

  1. 如果sshd服务没有运行,则报告sshd服务状态到/tmp/sshd_status.log日志;同时启动sshd服务,启动的结果也写入/tmp/sshd_status.log日志。
  2. 如果sshd服务正常运行,则报告sshd服务状态,并写入/tmp/sshd_status.log日志
  3. 每隔3秒执行一次监控。

monitor_sshd.sh 脚本内容如下:

#!/bin/bash

log_file=/tmp/sshd_status.log

while true
do
  status=$(systemctl is-active sshd)

  if [ "$status" == "active" ];then
     echo "$(date): sshd status is running." | tee -a ${log_file}
  else
     echo "$(date): sshd status is not running." | tee -a ${log_file}
     systemctl start sshd &>/dev/null && \
     echo "$(date): Start sshd success." |tee -a ${log_file} || \
     echo "$(date): Start sshd fail." |tee -a ${log_file}
  fi
  sleep 3

done

执行效果如下:

[root@CentOS bin 17:11:34]# bash monitor_sshd.sh 
2026年 04月 13日 星期一 17:11:42 CST: sshd status is running.
2026年 04月 13日 星期一 17:11:45 CST: sshd status is running.
2026年 04月 13日 星期一 17:11:48 CST: sshd status is running.
...

新开终端关闭sshd服务,监控日志变化

[root@CentOS ~ 15:55:51]# systemctl stop sshd

日志内容刷新如下:

2026年 04月 13日 星期一 17:12:41 CST: sshd status is running.
2026年 04月 13日 星期一 17:12:44 CST: sshd status is not running.
2026年 04月 13日 星期一 17:12:44 CST: Start sshd success.
2026年 04月 13日 星期一 17:12:47 CST: sshd status is running.
2026年 04月 13日 星期一 17:12:50 CST: sshd status is running.
Logo

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

更多推荐