Shell脚本条件判断#

条件判断是Shell脚本中实现逻辑控制的核心机制,允许脚本根据不同的条件执行不同的命令。本教程将详细介绍Shell中的各种条件判断语句,从基础的if语句到复杂的逻辑组合。

入门#

基本if语句#

if语句是Shell中最基本的条件判断结构,用于根据条件的真假执行不同的命令。

# 基本if语句
if [ condition ]; then
    # 条件为真时执行的命令
fi

# 示例:检查文件是否存在
if [ -f "file.txt" ]; then
    echo "文件存在"
fi

# if-else语句
if [ -f "file.txt" ]; then
    echo "文件存在"
else
    echo "文件不存在"
fi

# if-elif-else语句
if [ $USER = "root" ]; then
    echo "您是root用户"
elif [ $USER = "admin" ]; then
    echo "您是admin用户"
else
    echo "您是普通用户"
fi

测试命令#

Shell中的测试命令用于检查条件是否成立,有两种形式:[ condition ]test condition

# 测试文件状态
[ -f "file.txt" ]  # 检查是否为普通文件
[ -d "dir" ]       # 检查是否为目录
[ -e "path" ]      # 检查路径是否存在
[ -s "file.txt" ]  # 检查文件是否非空

# 测试字符串
[ -z "string" ]    # 检查字符串是否为空
[ -n "string" ]    # 检查字符串是否非空
[ "$a" = "$b" ]   # 检查字符串是否相等
[ "$a" != "$b" ]  # 检查字符串是否不相等

# 测试数字
[ $a -eq $b ]      # 检查数字是否相等
[ $a -ne $b ]      # 检查数字是否不相等
[ $a -lt $b ]      # 检查a是否小于b
[ $a -le $b ]      # 检查a是否小于等于b
[ $a -gt $b ]      # 检查a是否大于b
[ $a -ge $b ]      # 检查a是否大于等于b

中级#

高级测试操作#

逻辑运算符#

# 逻辑与 -a 或 &&
if [ -f "file.txt" -a -r "file.txt" ]; then
    echo "文件存在且可读"
fi

# 使用&&的另一种形式
if [ -f "file.txt" ] && [ -r "file.txt" ]; then
    echo "文件存在且可读"
fi

# 逻辑或 -o 或 ||
if [ -f "file1.txt" -o -f "file2.txt" ]; then
    echo "至少有一个文件存在"
fi

# 逻辑非 !
if [ ! -f "file.txt" ]; then
    echo "文件不存在"
fi

双括号语法#

(( ))语法用于算术运算和比较,支持C风格的语法。

# 算术比较
if (( 10 > 5 )); then
    echo "10大于5"
fi

# 使用变量
x=10
y=5
if (( x > y )); then
    echo "$x大于$y"
fi

# 支持的运算符: +, -, *, /, %, ==, !=, <, <=, >, >=, &&, ||, !

双方括号语法#

[[ ]]语法是bash的扩展,提供了更强大的字符串处理能力。

# 字符串比较
if [[ "$string" == "test" ]]; then
    echo "字符串匹配"
fi

# 模式匹配
if [[ "$string" == t* ]]; then
    echo "字符串以t开头"
fi

# 正则表达式匹配
if [[ "$string" =~ ^[0-9]+$ ]]; then
    echo "字符串是数字"
fi

# 逻辑运算符
if [[ -f "file.txt" && -r "file.txt" ]]; then
    echo "文件存在且可读"
fi

高级#

case语句#

case语句用于多条件分支判断,比多个if-elif语句更简洁。

# 基本case语句
case $variable in
    pattern1)
        # 匹配pattern1时执行的命令
        ;;
    pattern2)
        # 匹配pattern2时执行的命令
        ;;
    *)
        # 匹配所有其他情况时执行的命令
        ;;
esac

# 示例:菜单选择
read -p "请选择 (1-3): " choice
case $choice in
    1)
        echo "您选择了选项1"
        ;;
    2)
        echo "您选择了选项2"
        ;;
    3)
        echo "您选择了选项3"
        ;;
    *)
        echo "无效选择"
        ;;
esac

# 模式匹配
case $filename in
    *.txt)
        echo "文本文件"
        ;;
    *.sh)
        echo "Shell脚本"
        ;;
    *.jpg|*.png)
        echo "图片文件"
        ;;
    *)
        echo "其他文件"
        ;;
esac

条件表达式#

命令执行结果作为条件#

# 命令执行成功(退出状态为0)作为条件
if grep -q "pattern" "file.txt"; then
    echo "文件中包含pattern"
fi

# 命令执行失败作为条件
if ! cp "file.txt" "backup.txt"; then
    echo "复制失败"
fi

# 组合命令
if command1 && command2; then
    echo "两个命令都执行成功"
fi

特殊条件判断#

# 检查命令是否存在
if command -v git > /dev/null 2>&1; then
    echo "git已安装"
else
    echo "git未安装"
fi

# 检查操作系统类型
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
    echo "Linux系统"
elif [[ "$OSTYPE" == "darwin"* ]]; then
    echo "macOS系统"
elif [[ "$OSTYPE" == "cygwin" ]]; then
    echo "Cygwin"
elif [[ "$OSTYPE" == "msys" ]]; then
    echo "MSYS/MinGW"
else
    echo "未知系统: $OSTYPE"
fi

# 检查用户权限
if [ $(id -u) -eq 0 ]; then
    echo "您是root用户"
else
    echo "您不是root用户"
fi

大师#

高级条件结构#

单行条件语句#

# 单行if语句
if [ -f "file.txt" ]; then echo "文件存在"; fi

# 使用&&和||的简写形式
[ -f "file.txt" ] && echo "文件存在" || echo "文件不存在"

# 命令执行的条件判断
command && echo "成功" || echo "失败"

嵌套条件#

# 嵌套if语句
if [ -d "dir" ]; then
    if [ -w "dir" ]; then
        if [ -x "dir" ]; then
            echo "目录存在且可写可执行"
        else
            echo "目录存在且可写但不可执行"
        fi
    else
        echo "目录存在但不可写"
    fi
else
    echo "目录不存在"
fi

# 复杂的case语句
case $option in
    [0-9])
        echo "单个数字"
        ;;
    [a-z])
        echo "小写字母"
        ;;
    [A-Z])
        echo "大写字母"
        ;;
    *)
        case $option in
            quit|exit)
                echo "退出"
                ;;
            help|?)
                echo "帮助"
                ;;
            *)
                echo "其他选项"
                ;;
        esac
        ;;
esac

性能优化#

# 短路评估
# 避免不必要的测试
if [ -f "file.txt" ] && [ $(wc -l < "file.txt") -gt 10 ]; then
    echo "文件存在且行数超过10"
fi

# 先检查最可能失败的条件
# 例如,文件存在性检查比内容检查快
if [ -f "large_file.txt" ] && grep -q "pattern" "large_file.txt"; then
    echo "文件存在且包含pattern"
fi

# 使用缓存避免重复计算
file_count=$(ls -l | wc -l)
if [ $file_count -gt 0 ]; then
    echo "目录中有$file_count个文件"
    # 后续可以重复使用$file_count变量
fi

无敌#

高级条件技巧#

函数式条件#

# 使用函数作为条件
is_root() {
    [ $(id -u) -eq 0 ]
}

if is_root; then
    echo "您是root用户"
else
    echo "您不是root用户"
fi

# 返回状态的函数
check_file() {
    local file="$1"
    [ -f "$file" ] && [ -r "$file" ] && [ -s "$file" ]
}

if check_file "important.txt"; then
    echo "文件有效"
else
    echo "文件无效"
fi

动态条件#

# 动态生成条件
condition="-f file.txt -a -r file.txt"
if eval "[ $condition ]"; then
    echo "条件成立"
fi

# 使用数组存储条件
conditions=(
    "-f file.txt"
    "-r file.txt"
    "-s file.txt"
)

all_true=1
for cond in "${conditions[@]}"; do
    if ! eval "[ $cond ]"; then
        all_true=0
        break
    fi
done

if [ $all_true -eq 1 ]; then
    echo "所有条件都成立"
else
    echo "至少有一个条件不成立"
fi

实用脚本示例#

系统检查脚本#

#!/bin/bash

# 系统检查脚本
echo "===== 系统检查 ====="

# 检查磁盘空间
if [ $(df -h / | tail -n 1 | awk '{print $5}' | sed 's/%//') -gt 90 ]; then
    echo "警告:根分区空间不足"
else
    echo "根分区空间正常"
fi

# 检查内存使用
if [ $(free -m | grep Mem | awk '{print $3}') -gt $(free -m | grep Mem | awk '{print $2}')*0.8 ]; then
    echo "警告:内存使用过高"
else
    echo "内存使用正常"
fi

# 检查关键服务
for service in sshd nginx mysql; do
    if systemctl is-active --quiet $service; then
        echo "服务 $service 运行正常"
    else
        echo "警告:服务 $service 未运行"
    fi
done

echo "===== 检查完成 ====="

备份脚本#

#!/bin/bash

# 备份脚本
backup_dir="/backup"
source_dirs=("/etc" "/home" "/var/www")

date=$(date +%Y-%m-%d)

# 检查备份目录
if [ ! -d "$backup_dir" ]; then
    echo "创建备份目录: $backup_dir"
    mkdir -p "$backup_dir"
fi

# 执行备份
for dir in "${source_dirs[@]}"; do
    if [ -d "$dir" ]; then
        backup_file="$backup_dir/$(basename $dir)-$date.tar.gz"
        echo "备份 $dir$backup_file"
        tar -czf "$backup_file" "$dir"
        
        # 检查备份是否成功
        if [ $? -eq 0 ]; then
            echo "备份成功"
        else
            echo "备份失败"
        fi
    else
        echo "目录 $dir 不存在,跳过"
    fi
done

# 清理旧备份(保留最近7天)
echo "清理7天前的旧备份"
find "$backup_dir" -name "*.tar.gz" -mtime +7 -delete

echo "备份任务完成"

总结#

条件判断是Shell脚本中实现逻辑控制的核心机制,通过掌握if语句、case语句、测试命令和各种条件表达式,您可以创建更加智能和灵活的Shell脚本。从简单的文件检查到复杂的系统管理,条件判断无处不在。

随着您对Shell条件判断的理解不断深入,您将能够编写更加健壮、可靠的Shell脚本,处理各种复杂的场景和边缘情况。记住,良好的条件判断逻辑是构建高质量Shell脚本的基础。