我正在编写一个非常简单的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条答案
按热度按时间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的评论所指出的,注解代码并将其链接到这里是一个好主意,这样未来的开发人员就知道你的意思了!
9rygscc12#
$(())
用于算术表达式,而大括号扩展在算术中不进行。创建一个循环数组:
s1ag04yj3#
printf %4d $(({1..10}*i))
由于
bash
中展开参数的顺序,因此不起作用。大括号展开({}
)比算术展开($(())
)早完成bash
。你的代码肯定会工作,如果它是相反的方式。从
man bash
:展开的顺序是:撑条膨胀;波浪号扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);字分裂;和路径名扩展。
pkmbmrz74#
遇到过这样的狂欢这个问题要求解释,而不是解决方案,但这里将是一个$(())-表达这一点的方式。
像参数展开一样,在算术展开中禁止大括号展开。
(bash手册)
为避免与参数展开发生冲突,字符串“${”不适合大括号展开,并且在结束“}”之前禁止大括号展开。