shell 为什么bash括号扩展在某些算术表达式中有效,而在其他表达式中无效?

xmd2e60i  于 2023-06-30  发布在  Shell
关注(0)|答案(4)|浏览(125)

我正在编写一个非常简单的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")

如果能帮上忙我会很感激的。

xcitsw88

xcitsw881#

为1990年的机器设定了回归之路。
Bash根据POSIX P1003.2d9(大约1990年)实现了$[]语法,这是发布的P1003.2-1992的草案。在草案和标准之间的两年时间里,POSIX已经确定了ksh 88 $(())的语法和行为。Chet Ramey(bash维护者)说,back in 2012
Bash...实现了$[...],因为当时没有其他语法,并获得了一些在shell中进行算术扩展的操作经验。Bash-1.14...列出了两种形式的算术扩展,但是到1995年bash-2.0发布时,手册只提到了$((...))形式。
这表明$[]形式是 * 实验性的 *,它具有某些行为(如大括号扩展),当POSIX采用$(())语法时,这些行为被指定为遗忘。这些实验行为被保留了下来,因为已经有脚本依赖于它们(记住已经过去了两年多)。
Chet在同一个线程中明确表示,$[]已经过时,但并没有被弃用:
现在,继续拖动$[...]语法几乎没有任何问题。它只需要几十个字节的代码。我不打算删除它。
current POSIX standard, C.2.6 Word Expansions > Arithmetic Expansion提到了语法(重点是我的):
在早期的提案中,使用了$[expression]的形式。它在功能上等同于当前文本中的“$(())”,但有人提出反对意见,认为1988年的KornShell已经实现了“$(())”,没有令人信服的理由再发明另一种语法。此外,“$[]”语法在case语句中的模式方面有一个小的不兼容性。
因此,bash中实现的行为并不完全符合规范,但由于没有删除它的计划,如果它能巧妙地解决您的问题,我认为没有理由放弃它的好处。然而,正如@Barmar的评论所指出的,注解代码并将其链接到这里是一个好主意,这样未来的开发人员就知道你的意思了!

9rygscc1

9rygscc12#

$(())用于算术表达式,而大括号扩展在算术中不进行。
创建一个循环数组:

for i in {1..10}
do
    vals=()
    for j in {1..10}
    do
        vals+=($((i*j)))
    done
    printf "%4d" ${vals[@]}
done
s1ag04yj

s1ag04yj3#

printf %4d $(({1..10}*i))
由于bash中展开参数的顺序,因此不起作用。大括号展开({})比算术展开($(()))早完成bash。你的代码肯定会工作,如果它是相反的方式。
man bash
展开的顺序是:撑条膨胀;波浪号扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);字分裂;和路径名扩展。

pkmbmrz7

pkmbmrz74#

遇到过这样的狂欢这个问题要求解释,而不是解决方案,但这里将是一个$(())-表达这一点的方式。

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

像参数展开一样,在算术展开中禁止大括号展开。
(bash手册)
为避免与参数展开发生冲突,字符串“${”不适合大括号展开,并且在结束“}”之前禁止大括号展开。

相关问题