一、 数值运算 (Numerical Operations)
Shell中进行数值运算有多种方式,每种方式有其特定的应用场景和优缺点。
1. 常见运算方式对比
| 运算方式 | 语法示例 | 支持小数 | 效率 | 说明 |
|---|---|---|---|---|
$(()) | echo $((1+1)) | ❌ 否 | ⭐⭐⭐⭐⭐ | 推荐。Shell内置,效率最高,无需转义 *。 |
$[] | echo $[1+1] | ❌ 否 | ⭐⭐⭐⭐ | 较老式的写法,功能同 $(())。 |
expr | expr 1 + 1 | ❌ 否 | ⭐⭐⭐ | 外部命令,效率较低。注意运算符两边必须有空格,* 需要转义为 \*。 |
let | let i++ | ❌ 否 | ⭐⭐⭐⭐ | 主要用于变量赋值和自增/自减操作。 |
bc | echo "1.5+1" | bc | ✅ 是 | ⭐⭐ | 任意精度计算器,适合浮点数运算。 |
awk | echo 10 3 | awk '{print $1/$2}' | ✅ 是 | ⭐⭐ | 文本处理神器,也擅长数值计算。 |
python | python -c "print(1+1)" | ✅ 是 | ⭐ | 调用Python解释器,功能最强但开销大。 |
2. 深入解析
2.1 expr 命令的坑
- 空格敏感:
expr 1+1不会进行计算,只会输出字符串1+1。必须写成expr 1 + 1。 - 乘法转义:
expr 2 * 3会报错,因为*是通配符。必须写成expr 2 \* 3。 - 返回值:
expr常用于判断参数是否为整数。如果计算结果非空且非0,返回码为0(成功);否则可能非0。
2.2 let 命令技巧
let 不需要 $ 符号来引用变量,非常适合循环中的计数器。
let i++ # 等同于 i=$((i+1))
let a=a+5
2.3 小数运算 (bc & awk)
Shell原生不支持小数,需借助工具:
# 使用 bc
echo "10 / 3" | bc -l # -l 加载数学库,支持小数
# 使用 awk (推荐,格式化输出更方便)
echo 10 3 | awk '{printf "%.2f\n", $1/$2}' # 输出 3.33
二、 变量子串操作 (String Manipulation)
Shell 提供了强大的内置字符串处理功能,无需调用 sed 或 awk 即可完成简单的替换和截取,效率极高。
1. 字符串截取与删除
假设变量 url="www.sina.com.cn"
| 符号 | 记忆口诀 | 示例 | 结果 | 说明 |
|---|---|---|---|---|
# | 键盘上 # 在 $ 左边 -> 从左往右删 | ${url#*.} | sina.com.cn | 非贪婪匹配(最短匹配),删掉第一个 . 及其左边 |
## | 两个 # -> 贪婪删 | ${url##*.} | cn | 贪婪匹配(最长匹配),删掉最后一个 . 及其左边 (常用于获取后缀) |
% | 键盘上 % 在 $ 右边 -> 从右往左删 | ${url%.*} | www.sina.com | 非贪婪匹配,删掉最后一个 . 及其右边 |
%% | 两个 % -> 贪婪删 | ${url%%.*} | www | 贪婪匹配,删掉第一个 . 及其右边 |
2. 字符串替换
| 语法 | 说明 | 示例 (url=www.baidu.com) | 结果 |
|---|---|---|---|
${var/old/new} | 替换第一个匹配项 | ${url/baidu/sina} | www.sina.com |
${var//old/new} | 替换所有匹配项 | ${url//w/W} | WWW.baidu.com |
${var/old/} | 删除第一个匹配项 | ${url/baidu/} | www..com |
3. 获取长度
echo ${#url} # 输出字符串长度
三、 条件表达式 (Conditional Expressions)
1. 语法结构
test 表达式[ 表达式 ]:最常用,注意[后和]前必须有空格。[[ 表达式 ]]:Bash 扩展语法,支持正则匹配~=,逻辑运算符&&||可直接在内部使用。
2. 文件判断 (File Tests)
| 参数 | 说明 | 记忆 |
|---|---|---|
-f | 判断是否为普通文件 (file) 且存在 | file |
-d | 判断是否为目录 (directory) 且存在 | directory |
-e | 判断文件或目录是否存在 (exist) | exist |
-r | 判断是否有读权限 | read |
-w | 判断是否有写权限 | write |
-x | 判断是否有可执行权限 | execute |
3. 字符串比对
| 运算符 | 说明 | 示例 |
|---|---|---|
= / == | 相等 | [ "$a" = "$b" ] |
!= | 不等 | [ "$a" != "$b" ] |
-z | 长度为0 (Zero) | [ -z "$name" ] (判断空变量) |
-n | 长度不为0 (Non-zero) | [ -n "$name" ] |
=~ | 正则匹配 (仅 [[ ]]) | [[ "$name" =~ ^[0-9]+$ ]] |
4. 整数比对
| 运算符 | 英文全称 | 含义 |
|---|---|---|
-eq | equal | 等于 |
-ne | not equal | 不等于 |
-gt | greater than | 大于 |
-ge | greater or equal | 大于等于 |
-lt | less than | 小于 |
-le | less or equal | 小于等于 |
5. 逻辑运算符
| 关系 | [ ] 内部语法 | [[ ]] 或 外部语法 | 说明 |
|---|---|---|---|
| 与 (AND) | -a | && | 两边都成立才为真 |
| 或 (OR) | -o | || | 只要一边成立即为真 |
| 非 (NOT) | ! | ! | 取反 |
示例:
[ -f /etc/hosts -a -d /etc ] && echo "Ok" # [ ] 内部用 -a
[ -f /etc/hosts ] && [ -d /etc ] && echo "Ok" # 外部用 &&
[[ -f /etc/hosts && -d /etc ]] && echo "Ok" # [[ ]] 内部用 &&
四、 实战案例 (Practical Examples)
案例 1:检查输入是否为整数
利用正则匹配 [[ =~ ]] 是最简便的方法。
#!/bin/bash
read -p "请输入一个数字: " num
# 判断是否为纯数字
if [[ ! "$num" =~ ^[0-9]+$ ]]; then
echo "错误:请输入纯整数!"
exit 1
fi
echo "你输入的数字是:$num"
案例 2:磁盘空间监控告警
监控根分区使用率,超过 10% (测试用,实际可设 80%) 发送告警。
#!/bin/bash
# 1. 获取磁盘使用率 (去除百分号)
disk_use=$(df -h | awk '/\/$/ {print $(NF-1)}' | sed 's/%//')
# 2. 判断是否超过阈值
if [ "$disk_use" -gt 10 ]; then
echo "警告:磁盘使用率过高,当前为 ${disk_use}%"
# 此处可调用发送邮件或微信脚本
# python weixin.py "Disk Alert" "Usage: ${disk_use}%"
else
echo "磁盘状态正常:${disk_use}%"
fi
案例 3:服务自愈脚本 (Nginx)
判断服务是否存在,不存在则尝试启动。
#!/bin/bash
# 检查 Nginx 进程是否存在
# wc -l 统计行数,如果为0说明没运行
count=$(ps -ef | grep nginx | grep -v grep | wc -l)
if [ "$count" -eq 0 ]; then
echo "Nginx 未运行,正在尝试启动..."
systemctl start nginx
# 再次检查
if [ $? -eq 0 ]; then
echo "Nginx 启动成功"
else
echo "Nginx 启动失败,请人工介入!"
fi
else
echo "Nginx 正在运行中"
fi
案例 4:自动创建目录
#!/bin/bash
DIR="/data/backup"
# 如果目录不存在,则创建
if [ ! -d "$DIR" ]; then
echo "目录 $DIR 不存在,正在创建..."
mkdir -p "$DIR"
fi
cd "$DIR" || exit
echo "已进入目录 $(pwd)"
Comments NOTHING