0

i learned bash very recently, and i'm trying to read arguments for my script. So i wrote this, but i get an error (and vim has highlited in pink the last double parenthesis in the 4th line)

#!/bin/bash
for (( i=1; i<=$#; i++ )); do
  if [[ ${!i:0:1} == "-" ]] && ! [[ ${!i:1} =~ [^a-zA-Z]+ ]]; then
    for (( j=1; j<=$(($(expr length ${!i})-1)); j++ )); do
      if [[ ${!i:j:1} == "s" ]]; then
        k=$((i+1))
        if [ -e ${!k} ]; then
          echo $(realpath ${!k})
        fi
      elif [[ ${!i:j:1} == "o" ]]; then
        echo "Running script without output!"
      fi
    done
  fi
done

I get the following error when i run ./test -so doc1

./tests2: line 13: syntax error near unexpected token `newline'
./tests2: line 13: `    done'

Can anyone help me understand what's wrong with my script?

4
  • 1
    Usually, if you are using indices, you are doing something wrong. What is it you are actually trying to match? There is probably a much simpler, much more idiomatic solution. Commented Mar 19, 2017 at 23:47
  • I don't know what an indice is :S. But i was just trying to check for all the parameters given, and then check if a parameter contains multiple letters, such as "rm -rf ..." Commented Mar 19, 2017 at 23:53
  • Also, read about the getopts command in the bash man page. Commented Mar 19, 2017 at 23:54
  • Thanks for the hint on getopts i'll check that out! Commented Mar 20, 2017 at 0:07

2 Answers 2

3

It actually looks like you've encountered a bug in bash itself!

Bash fails to handle $(command substitution) when used inside $((arithmetic expansion)) inside arithmetic for loops:

$ for (( ; ; $(( $(echo 1) )) )); do echo "running"; break; done
bash: syntax error near unexpected token `newline'

It's not just an issue with the extra )): bash handles that nesting just fine:

$ for (( ; ; $(( 1 )) )); do echo "running"; break; done
running

And it works just fine with deprecated backticks instead of $(..)

$ for (( ; ; $(( `echo 1` )) )); do echo "running"; break; done
running

It's also fine within ((arithmetic commands)) in general, it's just arithmetic for loops that are affected:

$ while (( $(( $(echo 1) )) )); do echo "running"; break; done
running

So yes, congrats, it appears to be a bash bug! I don't know whether this is a known issue, but for now you can rewrite it as suggested in one of the other posts, or preferably use getopts.

Sign up to request clarification or add additional context in comments.

8 Comments

Well thanks for doing some tests regarding this and finding out it was a bug! Do you think i should rename my post to Potential bug in for loops (bash) ?
Of course, arithmetic expansion in a for loop is normally unnecessary since the for loop is already an arithmetic context. So there is an easy workaround.
Ahhh! Ok i was still not getting what those double parenthesis meant. I do understand now that those double parenthesis i added where useless, and it worked perfectly without them: for (( j=1; j<=$(expr length ${!i})-1; j++ )); do Thanks @rici!
@AmineKchouk: it is still a bug in bash and someone should report it.
Maybe it has been fixed in earlier versions. I just checked and i'm using Bash version 4.3.46(1), but you can see on Bash's website and they seem to be at version 4.4.12. I'm on Ubuntu 16.10 Server 64-bit, with apt packages up to date.
|
0

The issue is the nested (( ... )) in the inner for loop. You can change your code to this:

#!/bin/bash
for (( i=1; i<=$#; i++ )); do
  if [[ ${!i:0:1} == "-" ]] && ! [[ ${!i:1} =~ [^a-zA-Z]+ ]]; then
    lim=$(($(expr length ${!i})-1))
    for (( j=1; j<=$lim; j++ )); do
      if [[ ${!i:j:1} == "s" ]]; then
        k=$((i+1))
        if [[ -e ${!k} ]]; then
          echo $(realpath ${!k})
        fi
      elif [[ ${!i:j:1} == "o" ]]; then
        echo "Running script without output!"
      fi
    done
  fi
done

1 Comment

So i can't put a double parenthesis inside another double parenthesis?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.