Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bash arithmetic expansion diagnostics #255

Closed
mietek opened this issue Nov 10, 2014 · 7 comments
Closed

Bash arithmetic expansion diagnostics #255

mietek opened this issue Nov 10, 2014 · 7 comments

Comments

@mietek
Copy link

mietek commented Nov 10, 2014

In src/deploy.sh line 130:
        deploy_time=(( time_after - time_before ))
                    ^-- SC1056: Expected a '}'. If you have one, try a ; or \n in front of it.
                    ^-- SC1036: '(' is invalid here. Did you forget to escape it?
                    ^-- SC1072: Unexpected "(". Fix any mentioned problems and try again.
                     ^-- SC1036: '(' is invalid here. Did you forget to escape it?

The problem here is a missing $ before the ((. ShellCheck’s diagnostics appear to be misleading in this case.

@ormaaj
Copy link

ormaaj commented Jan 2, 2015

That might be tricky, because the parsing rules for array assignments are complex. In bash, x=((...)) is a special case of an invalid array assignment containing unescaped metacharacters. in ksh93, a=((foo)) is a perfectly valid array assignment to a[0][0]. And of course, it's also perfectly legal to have unescaped metacharacters even in bash array assignments such as typeset -ia a=([(x + y) * z]=foo.

It's also a special case of some closely related bugs (IMO). Bash incorrectly considers a=(foo)bar a valid string assignment and fails to split the assignment at the metacharacter ). ksh runs the bar command with a benign array export assignment (like bash would do if it split the words). In any shell without arrays it's just a plain invalid assignment.

Anyway, just sayin there's a lot to consider. I don't think just checking for a=(()) and assuming they meant $(()) is a good idea. That's more of a "typo" than anything else.

@brother
Copy link
Collaborator

brother commented Apr 1, 2015

I walked straight into one of these. It looks like something might have changed in bash on top of everything else because it was not new code that exploded in my face, but I have indeed a new bash version on this machine since last time I tried it.

brother ~$ cat /tmp/test.sh 
#!/bin/bash

slots=14

unset slotaddr
for ((i=0x82 ; i<((0x82+(slots*2))) ; i=i+2 )); do
    slotaddr+=($i)
done

echo "${slotaddr[@]}"
brother ~$ shellcheck /tmp/test.sh
brother ~$ /tmp/test.sh
/tmp/test.sh: command substitution: line 9: syntax error near unexpected token `slots*2'
/tmp/test.sh: command substitution: line 9: `(0x82+(slots*2))) ; i=i+2 '
/tmp/test.sh: line 6: syntax error: arithmetic expression required
/tmp/test.sh: line 6: syntax error: `((i=0x82 ; i<((0x82+(slots*2))) ; i=i+2 ))'

on bash 4.3.30(1)-release

after adding the missing $ (took me a good while to understand how this suddenly could just break =)) I get the expected output ofc.

brother ~$ cat /tmp/test.sh 
#!/bin/bash

slots=14

unset slotaddr
for ((i=0x82 ; i<$((0x82+(slots*2))) ; i=i+2 )); do
    slotaddr+=($i)
done

echo "${slotaddr[@]}"
brother ~$ shellcheck /tmp/test.sh
brother ~$ LC_ALL=C /tmp/test.sh
130 132 134 136 138 140 142 144 146 148 150 152 154 156

@brother
Copy link
Collaborator

brother commented Apr 1, 2015

oh. adding a space between < and (( makes bash happy. I do not know enough about the environment to point fingers here.

@ormaaj
Copy link

ormaaj commented Apr 1, 2015

On Wed, Apr 1, 2015 at 7:07 AM, brother notifications@github.com wrote:

I walked straight into one of these. It looks like something might have
changed in bash on top of everything else because it was not new code that
exploded in my face, but I have indeed a new bash version on this machine
since last time I tried it.

brother ~$ cat /tmp/test.sh #!/bin/bash

slots=14
unset slotaddrfor ((i=0x82 ; i<((0x82+(slots_2))) ; i=i+2 )); do
slotaddr+=($i)done
echo "${slotaddr[@]}"
brother ~$ shellcheck /tmp/test.sh
brother ~$ /tmp/test.sh
/tmp/test.sh: command substitution: line 9: syntax error near unexpected token slots_2'/tmp/test.sh: command substitution: line 9: (0x82+(slots2))) ; i=i+2 '/tmp/test.sh: line 6: syntax error: arithmetic expression required/tmp/test.sh: line 6: syntax error:`((i=0x82 ; i<((0x82+(slots2))) ; i=i+2 ))'

on bash 4.3.30(1)-release

​That's a bug​. There were some changes to the way C-for was parsed during
4.2. Or it's possibly related to when process substitution was removed from
certain arithmetic contexts during that time.

@ormaaj
Copy link

ormaaj commented Apr 1, 2015

Forwarded your issue to bug-bash since that should probably be fixed. http://article.gmane.org/gmane.comp.shells.bash.bugs/23373

EDIT: ...and it's fixed. I guess this one didn't get a backport to 4.3.

@brother
Copy link
Collaborator

brother commented Apr 2, 2015

@ormaaj gee. thanks!

@koalaman
Copy link
Owner

Great edge case. Warnings have been much improved in 3cf8b9c

In foo line 3:
var=((foo+1))
    ^-- SC1116: Missing $ on a $((..)) expression? (or use ( ( for arrays).

In addition to this warning, it's now being parsed as a multidimensional array, so it may be followed by a pile of array warnings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants