2

我创建了一个执行计算的脚本。例如: count 1 + 3

1 + 3 = 4, -/可以,但是如果我输入 count 1 * 3,我得到了

应该是数字操作数

这是脚本的一部分:

if [ "$#" -ne 3 ]; then
        echo "Should be number operand number"
        exit 1
fi
...
elif [ "$2" = "*" ]; then
        result=`echo $1 \* $3 | bc`
  echo "$1 * $3 = $result"

是的,如果我\之前*在命令行中输入它会起作用,但我需要它只使用*.

我尝试-f在脚本中使用 set 它不起作用(是的,如果我输入 bash 本身,它会禁用特殊字符,但这不是我需要的)。还有一个shopt控制 shell 行为的命令,所以我尝试启用一些选项,如shopt -s globstar, nullglob,promptvars等。它不起作用。我把命令放在 if 语句之前可能是错误的。

如果有人纠正我或告诉其他方式来禁用脚本内部对特殊字符的解释,我将不胜感激。

4

2 回答 2

2

expr 的 POSIX 规范中提到了这个确切的问题,因为您描述的原因,该工具具有“相当困难的语法”。

换句话说,这绝对是一个已知问题,而 POSIX 本身没有解决它。你真的应该考虑使用 Unix 并做同样的事情,而不是试图反对它。

一些选项是:

  • 要求一个引用参数的整个表达式,例如count "1 * 2"

    这是确保始终引用参数的实用、快速失败的方法,因此任何 * 的引入仍然有效。内置的 bashlet执行此操作。

  • read您自己的表达式,例如只需运行count然后输入1 * 2.

    这样可以避免外壳接触您的数据,以便您可以随意解释它。这是什么bcdc做什么。

  • *接受传递需要仔细引用的事实。

    这就是这样expr做的。

  • 使用仅在特定情况下适用于某些 shell的魔术别名hack。

    这是没有人会做的,因为它是脆弱和不可预测的,即使它在某些情况下允许你想要的语法。

于 2016-06-10T00:28:56.497 回答
0

当你回应时总是引用。您还需要引用变量引用:

me$ FOO="BAR * BAR"
me$ echo "$FOO"
BAR * BAR

如果不使用双引号,bash 会看到*并执行文件名扩展*扩展到当前目录中的所有文件。

但是,在这样说时,您必须使用单引号来表示*

#!/bin/bash
if [ "$2" = "*" ]; then
    result=`echo $1 \* $3 | bc`
    echo "$1 * $3 = $result"
fi

以下将起作用:

» count.sh 2 '*' 1
2 * 2 = 4

在您的程序中您无能为力,因为*扩展是由 shell 完成的(与 Windows 相比,它是由​​程序完成的)。

这是另一个使用菜单驱动方法的代码示例:

#!/bin/bash
while true; do
    read -p "what's the first number? " n1
    read -p "what's the second number? " n2
    PS3="what's the operation? "
    select ans in add subtract multiply divide; do
        case $ans in 
            add) op='+' ; break ;;
            subtract) op='-' ; break ;;
            multiply) op='*' ; break ;;
            divide) op='/' ; break ;;
            *) echo "invalid response" ;;
        esac
    done
    ans=$(echo "$n1 $op $n2" | bc -l)
    printf "%s %s %s = %s\n\n" "$n1" "$op" "$n2" "$ans"
done

what's the first number? 5
what's the second number? 4
1) add
2) subtract
3) multiply
4) divide
what's the operation? /
invalid response
what's the operation? 4
5 / 4 = 1.25000000000000000000

简而言之,在不需要 shell 执行令牌拆分和通配符扩展的地方引用所有内容。

于 2016-06-09T23:57:44.157 回答