bashshellarithmetic-expressionsbrace-expansion

Why does bash brace expansion work in some arithmetic expressions but not others?


I am working on a very simple bash script and I'm having a problem with understating why deprecated $[] is working flawlessly, while $(()) seems to break the whole thing.

The code I'm referring to is:

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

In this version I am having no issues, yet I wouldn't like to use deprecated bash elements, that's why I wanted to switch to $(()).

Unfortunately, as soon as I change my code to:

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

I receive an error:

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

I'd be thankful for some help with this one...


Solution

  • Setting the way back machine for 1990.

    Bash implemented the $[] syntax per POSIX P1003.2d9 (circa 1990), which was a draft of the released P1003.2-1992. In the two years between draft and standard, POSIX had instead settled on the ksh88 $(()) syntax and behaviors. Chet Ramey (bash maintainer) had this to say, back in 2012:

    Bash... implemented $[...] because there was no other syntax at the time, and to gain some operational experience with arithmetic expansion in the shell. Bash-1.14... lists both forms of arithmetic expansion, but by the time bash-2.0 was released in 1995, the manual referred only to the $((...)) form.

    This suggests to me that the $[] form was experimental, and it had certain behaviors (like brace expansion) that were specified into oblivion when POSIX adopted the $(()) syntax. Those experimental behaviors were left in, since there were already scripts in the wild relying on them (remember more than 2 years had elapsed).

    Chet makes clear in that same thread that the $[] form is obsolete, but not deprecated:

    Now, it's hardly any problem to keep dragging the $[...] syntax along. It takes only a few dozen bytes of code. I have no plans to remove it.

    The current POSIX standard, C.2.6 Word Expansions > Arithmetic Expansion mentions the syntax (emphasis mine):

    In early proposals, a form $[expression] was used. It was functionally equivalent to the "$(())" of the current text, but objections were lodged that the 1988 KornShell had already implemented "$(())" and there was no compelling reason to invent yet another syntax. Furthermore, the "$[]" syntax had a minor incompatibility involving the patterns in case statements.

    So the as-implemented behavior in bash isn't quite to specification, but since there are no plans to remove it, I see no reason to forgo its benefits if it neatly solves your problem. However, as pointed out by @Barmar's comment, it'd be A Good Idea to comment the code and link it here so future developers know what the heck you mean!