【Shell 脚本编程】详细指南:第三章 - 运算符与条件判断
Shell 脚本编程详细指南:第三章 - 运算符与条件判断完全指南
引言:掌握Shell逻辑控制的核心
条件判断是Shell脚本实现复杂逻辑的基石。本章将深入解析各种运算符和条件判断结构,帮助您编写更健壮、更高效的脚本。我们将从基础语法入手,逐步探讨高级用法和最佳实践。
1. 数值运算的全面解析
1.1 五种数值计算方法对比
方法 | 示例 | 优点 | 缺点 |
---|---|---|---|
$(( )) | echo $((a * b)) | 高效,语法简洁 ,最常用 | Bash特有 |
expr | expr $a + $b | POSIX兼容 | 性能差,需要转义特殊字符 |
let | let sum=a+b | 可直接修改变量 | 可读性较差 |
bc | echo "5.2+3.8" | bc | 支持浮点数运算 | 需要外部命令 |
awk | awk "BEGIN{print $a/$b}" | 高精度计算 | 语法复杂 |
1.2 实际运算示例
整数运算:
a=15 b=4
echo "加法: $((a + b))" # 19
echo "取模: $((a % b))" # 3
echo "幂运算: $((a ** 2))" # 225
浮点运算(使用bc):
pi=$(echo "scale=10; 4*a(1)" | bc -l) # 计算π值
echo "圆周率: $pi" # 3.1415926535
位运算:
flags=5
echo "二进制: $((flags>>1))" # 2 (0101 → 0010)
2. 比较运算符深度剖析
2.1 数值比较运算符表
运算符 | 含义 | 等价数学符号 |
---|---|---|
-eq | 等于 | == |
-ne | 不等于 | != |
-gt | 大于 | > |
-ge | 大于等于 | >= |
-lt | 小于 | < |
-le | 小于等于 | <= |
2.2 字符串比较运算符表
运算符 | 含义 | 示例 |
---|---|---|
= | 相等 | [ "$str" = "test" ] |
!= | 不相等 | [[ "$str" != "" ]] |
< > | ASCII比较(需在[[ ]]中使用) | [[ "a" < "b" ]] |
=~ | 正则匹配(Bash扩展) | [[ "$str" =~ ^[0-9]+$ ]] |
-z | 空字符串 | [ -z "$var" ] |
-n | 非空字符串 | [ -n "$var" ] |
2.3 文件测试运算符
[ -e file ] # 存在
[ -f file ] # 是普通文件
[ -d file ] # 是目录
[ -r file ] # 可读
[ -w file ] # 可写
[ -x file ] # 可执行
[ -s file ] # 大小>0
[ file1 -nt file2 ] # file1比file2新
3. 条件判断结构详解
3.1 if语句的四种形式
基本形式:
if [ condition ]; thencommands
fi
if-else:
if [[ $num -gt 10 ]]; thenecho "大于10"
elseecho "小于等于10"
fi
if-elif-else:
if [ "$score" -ge 90 ]; thengrade="A"
elif [ "$score" -ge 80 ]; thengrade="B"
elsegrade="C"
fi
嵌套if:
if [ -f "$file" ]; thenif [ -s "$file" ]; thenecho "文件存在且非空"fi
fi
3.2 条件连接运算符
运算符 | 含义 | 示例 |
---|---|---|
&& | 逻辑与 | [ $a -gt 0 ] && [ $a -lt 10 ] |
|| | 逻辑或 | `[ -z “$str” ] |
! | 逻辑非 | if ! [ -d "$dir" ]; then |
4. 测试表达式进阶技巧
4.1 [ ] vs [[ ]] 对比
特性 | [ ] (test) | [[ ]] (Bash扩展) |
---|---|---|
字符串比较 | 支持 | 支持(更安全) |
模式匹配 | 不支持 | 支持(=~) |
逻辑运算 | -a/-o | &&/|| |
单词分割 | 会发生 | 不会发生 |
文件通配 | 会展开 | 不会展开 |
推荐实践:
# 使用[[ ]]避免变量引用问题
if [[ "$filename" == *.log ]]; thenecho "日志文件"
fi
4.2 正则表达式匹配
read -p "输入邮箱地址: " email
if [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; thenecho "有效邮箱"
elseecho "无效邮箱格式"
fi
5. 实战案例与解决方案
案例1:计算器脚本
#!/bin/bash
# calculator.shif [[ $# -ne 3 ]]; thenecho "用法: $0 数字 运算符 数字"echo "示例: $0 5 + 3"exit 1
ficase $2 in+) result=$(($1 + $3)) ;;-) result=$(($1 - $3)) ;;*) result=$(($1 * $3)) ;;/) [[ $3 -eq 0 ]] && { echo "错误: 除数不能为0"; exit 1; }result=$(echo "scale=2; $1 / $3" | bc) ;;%) result=$(($1 % $3)) ;;^) result=$(($1 ** $3)) ;;*) echo "不支持的操作符: $2"; exit 1 ;;
esacecho "结果: $result"
案例2:文件备份脚本
#!/bin/bash
# backup.shread -p "输入要备份的文件路径: " filepathif [[ ! -e "$filepath" ]]; thenecho "错误: 文件不存在" >&2exit 1
elif [[ ! -r "$filepath" ]]; thenecho "错误: 文件不可读" >&2exit 1
fibackup_dir="${HOME}/backups"
mkdir -p "$backup_dir"timestamp=$(date +%Y%m%d_%H%M%S)
filename=$(basename "$filepath")
backup_file="${backup_dir}/${filename}.${timestamp}.bak"if cp "$filepath" "$backup_file"; thenecho "备份成功: $backup_file"
elseecho "备份失败" >&2exit 1
fi
6. 最佳实践与常见陷阱
6.1 必须遵循的规范
-
变量引用:
# 正确 if [ "$var" -gt 0 ]; then# 危险 if [ $var -gt 0 ]; then
-
字符串比较:
# 使用双中括号避免分词 if [[ "$str" == "value" ]]; then
-
数值比较:
# 使用双括号进行算术比较 if ((num > max)); then
6.2 常见错误排查
问题1:未引用的变量导致语法错误
# 错误
if [ $var = "test" ]; then # 当$var为空时变成 [ = "test" ]# 正确
if [ "$var" = "test" ]; then
问题2:使用错误的比较运算符
# 错误:在[ ]中使用>进行字符串比较
if [ "$str1" > "$str2" ]; then# 正确
if [[ "$str1" > "$str2" ]]; then
进阶技巧
多条件测试优化
# 传统方式(创建子进程)
if [ "$a" -gt 0 ] && [ "$a" -lt 10 ]; then# 高效方式(Bash内置)
if [[ "$a" -gt 0 && "$a" -lt 10 ]]; then
使用算术表达式
# 在条件中直接计算
if (( (a + b) > (c * 2) )); thenecho "条件满足"
fi
本章总结
本章深入探讨了Shell脚本中的运算符和条件判断,重点包括:
- 五种数值运算方法的对比与选择
- 全面的比较运算符参考表
- 条件判断结构的各种形式与应用场景
- [ ]与[[ ]]的深度对比与选择建议
- 实际案例分析和最佳实践
🔍 下章预告:第四章将深入讲解循环结构(for/while/until)和流程控制(case/select),带您掌握Shell脚本的自动化处理能力。
互动练习:
编写一个脚本,实现以下功能:
- 检查/tmp目录是否存在
- 如果存在,统计其中的文件数量
- 根据文件数量输出不同消息:
- 空目录:0-5个文件
- 正常:6-20个文件
- 过多:20+个文件
欢迎在评论区分享您的实现方案!