为什么 ${*// /*} 不能在命令行参数中用 * 替换空格?

qou*_*ify 8 bash replace

我希望我的脚本执行其所有整数参数的乘积。我没有执行循环,而是尝试用替换空白*,然后计算操作。但我得到了以下我不明白的结果:

#!/bin/bash
# product.sh

echo $(( ${*// /*} ))  # syntax error with ./product.sh 2 3 4
args=$*
echo $(( ${args// /*} ))  # ./product.sh 2 3 4 => outputs 24
Run Code Online (Sandbox Code Playgroud)

当使用中间变量工作正常时,第一个会产生错误,这是怎么回事?

M. *_*din 10

第一个错误是如何产生的

\n来自Bash 参考手册

\n
\n

如果参数为 \xe2\x80\x98@\xe2\x80\x99 或 \xe2\x80\x98*\xe2\x80\x99,则依次对每个位置参数应用替换操作

\n
\n

(强调我的)
\n也就是说,表达式${*// /*}替换位置参数的空格,而不是分隔位置参数的空格。该表达式扩展为2 3 4(在算术上下文中使用时会出现语法错误),因为参数本身不包含空格。尝试用

\n
./product \'2 \' \'3 \' 4\n
Run Code Online (Sandbox Code Playgroud)\n

你会看到差异。

\n


anu*_*ava 6

您可以使用IFS

#!/bin/bash
# product.sh

# set IFS to *
IFS='*'

# use IFS in output
echo "$*"

# perform arithmetic
echo "$(( $* ))";
Run Code Online (Sandbox Code Playgroud)

输出:

2*3*4
24
Run Code Online (Sandbox Code Playgroud)


tri*_*eee 6

在您的示例中,该值$*实际上不包含任何文字空格,因此${*// /*}不执行任何操作。

如果确实如此,这些星号将受到通配符扩展的影响,因此即使可行,执行替换的想法似乎也相当脆弱。

我会简单地创建一个函数来处理参数,而不是依赖于替换的技巧——当参数之一是变量等时,这些往往会出现令人讨厌的极端情况。

mul () {
    case $# in
      [01]) echo "$@";;
      *) local n=$1; shift; echo $((n * $(mul "$@")));;
    esac
}
Run Code Online (Sandbox Code Playgroud)

  • 插入“*”的扩展值_直接在命令中使用_存在通配符(正式路径名扩展)的风险,但在算术“$(( ))”中则不然 (3认同)

Iva*_*van 5

或者使用printf,像这样:

echo $(( $(printf '%s*' $*)1 ))
Run Code Online (Sandbox Code Playgroud)