Why does the bash extension work in some arithmetic expressions, but not in others?

I am working on a very simple bash script, and I have an underestimation of why the deprecated $ [] works flawlessly, and $ (()) seems to break all of this.

The code that I mean is:

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

In this version, I have no problem, but I would not want to use obsolete bash elements, so I wanted to switch to $ (()).

Unfortunately, as soon as I change my code to:

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

I get an error message:

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

I would be grateful for the help in this ...

+2
bash brace-expansion
Oct 14 '16 at 1:19
source share
3 answers

Setting up the reverse machine for 1990.

Bash implemented the $[] syntax on POSIX P1003.2d9 (circa 1990), which was a project released by P1003.2-1992. For two years between the project and the POSIX standard, the syntax and behavior of ksh88 $(()) set instead. Chet Reime (bash escort) said the following: in 2012 :

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

This tells me that the $[] form was experimental, and it had a certain behavior (like curly brace extension) that was forgotten when POSIX adopted the $(()) syntax $(()) . Those experimental behaviors remained, since scenarios in the wild already existed relying on them (remember that more than two years have passed).

Chet clearly indicates that the form $[] deprecated, but not deprecated:

Now it’s hardly worth dragging the syntax of $ [...]. Only a few dozen bytes of code are required. I have no plans to remove it.

current POSIX standard, C.2.6 Word Extensions> Arithmetic extensions mention the syntax (my emphasis):

Earlier sentences used the form $ [expression]. It was functionally equivalent to the "$ (())" of the current text , but it was objected that KornShell already implemented "$ (())" in 1988, and there was no good reason to come up with another syntax. In addition, the syntax "$ []" was slightly incompatible, including patterns in case statements.

Thus, the behavior in bash is not completely specified, but since there are no plans to remove it, I see no reason to abandon its benefits if it accurately solves your problem. However, as @Barmar commented, it would be a good idea to comment on the code and link it here so that future developers know what the hell you mean!

+3
Oct 14 '16 at 17:28
source share

$(()) is for arithmetic expressions, and brace expansion is not performed 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 
+1
Oct. 14 '16 at 1:45
source share

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

does not work due to the order in which the parameters expand in bash . Bracket expansion ( {} ) is done earlier than arithmetic expansion ( $(()) ) in bash . Your code will definitely work if it were the other way around.

From man bash :

The order of decompositions: expansion of the bracket; tilde expansion, expansion of parameters and variables, arithmetic expansion and command substitution (performed from left to right); word splitting; and path name extension.

0
Oct 14 '16 at 18:56
source share



All Articles