简体   繁体   中英

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...

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!

$(()) is for arithmetic expressions, and brace expansion isn't done in arithmetic.

Make an array with a loop:

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

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

does not work because of the order in which parameters are expanded in bash . The brace expansion ( {} ) is done earlier than arithmetic expansion ( $(()) ) by bash . Your code would definitely work if it were other way around.

From man bash :

The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and pathname expansion.

Ran across some bash like this. This question asks for explanation, rather than solution, but here would be a $(())-way of expressing this.

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

Brace expansion is inhibited inside an arithmetic expansion like it is for parameter expansion.

(bash manual)

To avoid conflicts with parameter expansion, the string '${' is not considered eligible for brace expansion, and inhibits brace expansion until the closing '}'.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM