You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shell编写计算器时如何保留$变量解析并禁止*通配符展开

问题本质

你遇到的*通配符展开和脚本内部逻辑无关,是调用脚本的父Shell在启动脚本前就完成的替换:你敲完回车、脚本还没开始运行的时候,交互Shell就已经把未转义的*替换成当前目录下的所有文件名了。你在脚本内部给变量加引号根本拦不住这个阶段的展开,因为参数传到脚本里时,$2早就不是*了。
你之前测试引号的误区:

  • 双引号不是没用,是你加错了位置:双引号确实能阻止glob展开,但必须加在调用脚本的命令行里,加在脚本内部的变量上没有任何作用
  • 单引号会输出$1$2$3=字面量是bash的基础规则:单引号内部所有字符都按字面量处理,不会解析变量、执行转义
解决方案

规范调用方式(最稳妥无兼容问题)

只要在调用时把*转义,让父Shell不要展开它,你原来写的脚本不用改就能正常运行,三种合法转义写法任选其一即可:

  • 给*加单引号:calc 2 '*' 3
  • 给*加双引号:calc 2 "*" 3
  • 用反斜杠转义:calc 2 \* 3
    执行后都会正确输出2*3=6。

脚本兼容优化(用户无需转义也能运行)

如果不想让用户记转义规则,可以在脚本开头加参数校验逻辑,自动识别*被展开的场景,修正参数后再运算。优化后的完整脚本如下,顺便替换了效率更低的外部expr命令为bash原生算术扩展,补了除零判断,修正了拼写错误:

#!/bin/bash -u
PATH=/bin:/usr/bin ; export PATH
umask 022

num1=$1
op=$2
num2=$3

# 检测参数数量异常,判断是否为*被glob展开的场景
if [ $# -ne 3 ]; then
    # 校验首尾参数是否为整数,符合calc 数字 * 数字的调用特征
    if [[ $1 =~ ^-?[0-9]+$ && ${!#} =~ ^-?[0-9]+$ ]]; then
        op='*'
        num2=${!#}
    else
        echo "调用格式错误,正确用法:calc <数字> <运算符(+ - * /)> <数字>"
        exit 1
    fi
fi

echo -n "$num1$op$num2="

case "$op" in
'+' )   echo $((num1 + num2)) ;;
'-' )   echo $((num1 - num2)) ;;
'*' )   echo $((num1 * num2)) ;;
'/' )   
    if [ "$num2" -eq 0 ]; then
        echo "错误:除数不能为0"
        exit 1
    fi
    echo $((num1 / num2)) ;;
* )     echo 'unknown operation'  ;;
esac

这个兼容逻辑的原理是:如果用户输入calc 2 * 3时*被展开,传入脚本的参数会变成2 文件名1 文件名2 ... 3,此时参数数量肯定大于3,只要第一个和最后一个参数是合法整数,就可以判定中间的内容是被展开的*,直接取首尾参数作为运算数、运算符固定为*即可得到正确结果。

内容的提问来源于stack exchange,提问作者Ömer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.09 16:15:44