4

我正在编写一个非常简单的 bash 脚本,但我无法理解为什么不推荐使用的 $[] 可以完美地工作,而 $(()) 似乎破坏了整个事情。

我指的代码是:

for i in {1..10};
do 
    printf %4d $[{1..10}*i]
    echo
done

在这个版本中我没有任何问题,但我不想使用已弃用的 bash 元素,这就是我想切换到 $(()) 的原因。

不幸的是,一旦我将代码更改为:

printf %4d $(({1..10}*i))

我收到一个错误:

./script_bash.sh: line 8: {1..10}*i: syntax error: argument expected (error token is "{1..10}*i")

我会感谢一些帮助这个...

4

4 回答 4

4

为 1990 年设置回归机器。

Bash 实现了$[]每个 POSIX P1003.2d9(大约 1990 年)的语法,这是已发布的 P1003.2-1992 的草案。在草案和标准之间的两年时间里,POSIX 转而选择了 ksh88$(())语法和行为。Chet Ramey(bash 维护者)早在 2012 年就有这样的说法:

Bash... 之所以实现 $[...] 是因为当时没有其他语法,并且是为了获得一些在 shell 中进行算术扩展的操作经验。Bash-1.14... 列出了算术扩展的两种形式,但是到 1995 年 bash-2.0 发布时,该手册只提到了 $((...)) 形式。

这向我表明该$[]形式是实验性$(())的,并且当 POSIX 采用该语法时,它具有某些行为(如大括号扩展)被指定为遗忘。那些实验行为被留下了,因为野外已经有脚本依赖它们(记住已经过去了 2 年多)。

Chet 在同一个线程中明确表示该$[]表单已过时,但未弃用:

现在,继续拖动 $[...] 语法几乎没有任何问题。它只需要几十个字节的代码。我没有删除它的计划。

当前的POSIX 标准,C.2.6 Word Expansions > Arithmetic Expansion提到了语法(强调我的):

在早期的提案中,使用了 $[expression] 形式。它在功能上等同于当前文本的“$(())”,但有人反对 1988 年的 KornShell 已经实现了“$(())”,并且没有令人信服的理由来发明另一种语法。此外,"$[]" 语法与 case 语句中的模式有一点不兼容。

因此,bash 中实现的行为并不完全符合规范,但由于没有计划删除它,如果它巧妙地解决了您的问题,我认为没有理由放弃它的好处。但是,正如@Barmar 的评论所指出的那样,评论代码并将其链接到此处是一个好主意,以便未来的开发人员知道您的意思!

于 2016-10-14T17:28:49.593 回答
1

$(())用于算术表达式,而大括号扩展不是在算术中完成的。

用循环制作一个数组:

for i in {1..10}
do
    vals=()
    for j in {1..10}
    do
        vals+=($((i*j)))
    done
    printf "%4d" ${vals[@]}
done
于 2016-10-14T01:45:27.110 回答
1

printf %4d $(({1..10}*i))

由于参数在bash. 大括号扩展 ( {}) 比算术扩展 ( $(()))早完成bash。如果反过来,您的代码肯定会起作用。

来自man bash

展开顺序为:大括号展开;波浪号扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);分词;和路径名扩展。

于 2016-10-14T18:56:02.677 回答
0

遇到一些这样的bash。这个问题需要解释,而不是解决方案,但这里将是一种 $(()) 方式来表达这一点。

for i in {1..10}; do
  printf %4d $(eval echo '$(('{1..10}'*i))')
  echo
done

大括号扩展在算术扩展中被禁止,就像在参数扩展中一样。

(bash手册)

为避免与参数扩展发生冲突,字符串“${”不被视为符合大括号扩展的条件,并且在结束“}”之前禁止大括号扩展。

于 2019-11-02T15:39:57.963 回答