1. 项目概述
在Linux系统管理和日常开发中,Shell脚本是最基础也最实用的自动化工具。今天我要分享的是一个用Shell实现的简易计算器脚本,它不仅支持基础的加减乘除运算,还能处理带括号的表达式和小数运算。这个项目特别适合刚接触Shell脚本的新手练习,也适合作为日常快速计算的工具。
这个计算器的核心在于利用Shell的内置算术运算能力和expr命令,通过巧妙的字符串处理和递归调用实现运算符优先级。相比图形界面的计算器,它的优势在于可以轻松集成到其他脚本中,实现自动化计算流程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心功能解析
2.1 基本运算实现
Shell本身通过$(( ))语法支持整数运算,但我们需要更强大的功能:
bash复制# 加法示例
result=$((3 + 5)) # 输出8
# 使用expr的乘法(注意*需要转义)
result=$(expr 3 \* 5) # 输出15
对于小数运算,我们需要借助bc命令:
bash复制# 小数加法
result=$(echo "3.14 + 2.71" | bc) # 输出5.85
注意:直接使用expr处理小数会报错,必须使用bc计算器
2.2 括号优先级处理
实现括号优先级是最大的挑战,我采用递归方式解析:
bash复制calculate() {
local expr=$1
# 先处理最内层括号
while [[ $expr =~ \(([^()]+)\) ]]; do
local inner_expr=${BASH_REMATCH[1]}
local inner_result=$(calculate "$inner_expr")
expr=${expr//($inner_expr)/$inner_result}
done
# 然后处理无括号表达式
echo "$(compute "$expr")"
}
2.3 完整运算流程
- 输入表达式预处理:去除空格、统一运算符格式
- 括号递归解析:从最内层开始计算
- 运算符优先级处理:先乘除后加减
- 小数运算处理:自动切换到bc计算
- 结果输出:保留两位小数
3. 完整实现代码
以下是支持所有功能的完整脚本:
bash复制#!/bin/bash
# 主计算函数
compute() {
local expr=$1
# 处理乘除
while [[ $expr =~ ([0-9.]+)([*/])([0-9.]+) ]]; do
local a=${BASH_REMATCH[1]}
local op=${BASH_REMATCH[2]}
local b=${BASH_REMATCH[3]}
local result
if [[ $op == "*" ]]; then
result=$(echo "$a * $b" | bc)
else
result=$(echo "scale=4; $a / $b" | bc)
fi
expr=${expr//$a$op$b/$result}
done
# 处理加减
while [[ $expr =~ ([0-9.]+)([+-])([0-9.]+) ]]; do
local a=${BASH_REMATCH[1]}
local op=${BASH_REMATCH[2]}
local b=${BASH_REMATCH[3]}
local result=$(echo "$a $op $b" | bc)
expr=${expr//$a$op$b/$result}
done
echo "$expr"
}
# 括号处理函数
calculate() {
local expr=$1
# 递归处理括号
while [[ $expr =~ \(([^()]+)\) ]]; do
local inner=${BASH_REMATCH[1]}
local result=$(calculate "$inner")
expr=${expr//($inner)/$result}
done
# 计算无括号表达式
compute "$expr"
}
# 主程序
echo "Shell计算器 (输入q退出)"
while true; do
read -p "请输入表达式: " input
[[ "$input" == "q" ]] && break
# 预处理输入
input=$(echo "$input" | tr -d '[:space:]')
input=${input//×/*} # 兼容不同乘号
input=${input//÷/\/} # 兼容不同除号
# 计算并输出
result=$(calculate "$input")
printf "结果: %.2f\n" "$result"
done
4. 使用技巧与注意事项
4.1 输入格式建议
- 乘法建议使用*而非×(虽然脚本做了兼容)
- 除法使用/符号
- 括号必须成对出现
- 支持负数输入(如-3.5+2)
4.2 常见问题排查
-
语法错误提示
- 检查括号是否匹配
- 确认运算符两边都有操作数
- 小数点的格式是否正确(不能用逗号)
-
bc命令未找到
bash复制# 安装bc计算器 sudo apt-get install bc # Ubuntu/Debian sudo yum install bc # CentOS/RHEL -
除零错误
- 脚本不会捕获除零错误,需要用户自行避免
4.3 性能优化技巧
对于复杂表达式,可以添加预处理检查:
bash复制# 在calculate函数开头添加
if ! [[ "$expr" =~ ^[0-9.+\-*/() ]+$ ]]; then
echo "错误:包含非法字符" >&2
return 1
fi
5. 扩展功能实现
5.1 添加幂运算
修改compute函数,在处理乘除前先处理幂运算:
bash复制# 在compute函数开头添加
while [[ $expr =~ ([0-9.]+)\^([0-9.]+) ]]; do
local base=${BASH_REMATCH[1]}
local power=${BASH_REMATCH[2]}
local result=$(echo "$base^$power" | bc)
expr=${expr//$base^$power/$result}
done
5.2 添加历史记录功能
在脚本开头添加:
bash复制history_file="/tmp/shell_calc_history"
touch "$history_file"
在输出结果后添加:
bash复制echo "$(date '+%Y-%m-%d %H:%M:%S') | $input = $result" >> "$history_file"
5.3 转换为命令行工具
保存为/usr/local/bin/calc并添加执行权限:
bash复制sudo chmod +x /usr/local/bin/calc
然后可以直接在终端使用:
bash复制calc "3.14*(2+5)"
6. 实际应用案例
6.1 在监控脚本中使用
计算系统负载平均值:
bash复制#!/bin/bash
load1=$(uptime | awk -F'load average: ' '{print $2}' | cut -d, -f1)
load5=$(uptime | awk -F'load average: ' '{print $2}' | cut -d, -f2)
diff=$(calc "$load5 - $load1")
if [[ $(echo "$diff > 0.5" | bc) -eq 1 ]]; then
echo "警告:负载正在快速上升"
fi
6.2 财务计算示例
计算复利:
bash复制#!/bin/bash
principal=10000
rate=0.05
years=5
final=$(calc "$principal*(1+$rate)^$years")
echo "5年后本息合计: $final"
这个Shell计算器虽然简单,但通过逐步完善,已经能够处理大多数日常计算需求。我在多个自动化脚本中都使用了它的核心算法,特别是在需要动态计算的监控场景中表现非常可靠。
