8
x=1
while [ $x -le 50 ]
do
    echo $x
    $x=(($x + 1))
done

I have wrote the above code. What seems to be a easy task in many programming languages is giving this error for me.

solution.sh: line 5: syntax error near unexpected token `('
solution.sh: line 5: `    $x=(($x + 1))'

How to debug errors in bash. Is there any IDE?

WannaBeCoder
  • 225
  • 1
  • 3
  • 10
  • Use bash -x scriptname to debug. – jherran Dec 08 '14 at 11:51
  • 3
    There are 2 mistakes. The line should be x=$(($x + 1)). But easy to use seq instead all script seq 50 – Costas Dec 08 '14 at 11:52
  • Its working even if i do not keep a $ attached to x inside the parantheses. What is the difference – WannaBeCoder Dec 08 '14 at 11:53
  • 3
    Just so you know, in bash, you can do echo {1..50}. And in $(()) environment, the variables inside are automatically evaluated, which is why you don't need the $ inside it again. – muru Dec 08 '14 at 11:55
  • 1
    Thanks, @muru I started 10 mins back. thinking of doing it in normal way first. – WannaBeCoder Dec 08 '14 at 11:57
  • 1
    @WannaBeCoder you are using let and could also just do ((x++)). Also look up the let command. –  Dec 08 '14 at 12:01
  • If they use $(($x+1)) that will work but (($x+1)) will not, look on http://tldp.org/LDP/abs/html/arithexp.html for more info –  Dec 08 '14 at 12:03
  • @Jidder Since I specifically said $(()), I don't see how I am incorrect. See: https://www.gnu.org/software/bash/manual/html_node/Arithmetic-Expansion.html – muru Dec 08 '14 at 12:04
  • @muru Sorry, misread and thought OP was talking about their original code. –  Dec 08 '14 at 12:06

9 Answers9

15

A shell is not a (good) programming language, it's (before all) a command line interpreter. Use a counting command if you want to count, not the echo and [ commands in a loop.

For instance, GNU systems have the seq command for that. Alternatives are awk or bc for instance:

seq 50
echo 'for (i=1; i<=50; i++) i' | bc
awk 'BEGIN {for (i=1; i<= 50; i++) print i}'

If you find yourself using a loop in shells, chances are you're going for the wrong approach.

  • 3
    The beauty of Shell is that there are commands to do most things that are commonly useful but hard to implement. In this case, seq 50 is the one correct answer to OP's question: THIS is how you print numbers 1-50 in shell. – SF. Dec 08 '14 at 12:17
  • 2
    @SF. If you want shell, seq is hardly the 'right' way. echo {1..50} (or printf) would arguably be the shell way. – phemmer Dec 08 '14 at 12:21
  • 2
    Stéphane, I would only argue with you that there are plenty of times to use loops in bash. Looping is a basic programming construct, and is even applicable in shells (though admittedly, it makes more sense to use a foreach loop in most of those cases). – HalosGhost Dec 08 '14 at 12:36
  • 1
    @HalosGhost Perhaps Stephane prefers recursion to iteration. :) – muru Dec 08 '14 at 12:39
  • @muru, possible though that may be, I remain unconvinced that looping signals wrong-doing in shell. Additionally, I already said I typically prefer a foreach-style loop in most of those cases (which is often not strict iteration). – HalosGhost Dec 08 '14 at 12:41
11

Print numbers from 1-50

printf '%s\n' {1..50}

print numbers from 1-50 with step say 2 (bash 4+):

printf '%s\n' {1..50..2}
αғsнιη
  • 41,407
  • 1
    +1. Using the Bash builtins and avoiding interpreter-level loops makes this substantially faster than many of the other shell solutions, including my own. – CodeGnome Sep 15 '18 at 19:56
9

On line 5: Change $x=(($x + 1)) to x=$(($x + 1)).

Instead of using an entire bash script, you can just use seq 1 50.

If the case were x=$(($x + 2)), you could use seq 1 2 50, where 2 denotes step/increment.

  • Shouldn't that be x=$(( x + 1 )) ? No dollar symbol within the double brackets. – garethTheRed Dec 08 '14 at 12:28
  • 1
    @garethTheRed, $((x + 1)) would not work with some old versions of ash based shells, and is currently not clearly specified by POSIX (under discussion there) but would work in most shells nowadays. $(($x + 1)) is clearly specified but $((1-$x)) for instance has issues that $((1-x)) (or x=$((1-($x)))) don't have. x=$((x + 1)) is safe in modern versions of ash based shells even if x doesn't contain a number. Both have security implications in most other shells. – Stéphane Chazelas Dec 08 '14 at 12:38
  • 1
    @StéphaneChazelas the question is tagged bash. Does it matter what happens elsewhere? – muru Dec 08 '14 at 12:40
  • 2
    @muru, to many people, yes, it does. And my comment was not addressed to the OP (and besides is just general information on the benefit of either in the general case). – Stéphane Chazelas Dec 08 '14 at 12:46
  • @StéphaneChazelas - Before commenting, I tested x=$(($x + 1)) and it errored for me. I've tried it again and now it works. Aargh! – garethTheRed Dec 08 '14 at 12:48
  • @StéphaneChazelas - here there is this : ...intentionally silent about how a variable's numeric value in an expression is determined from its normal "sequence of bytes" value... conversions produce the same result...for x=010; echo $((x += 1)) the output must be 9. For the commands: x=' 1'; echo $((x += 1)) the results are unspecified. For the commands: x=1+1; echo $((x += 1)) the results are unspecified. ...is that what you mean by under discussion? is there more? – mikeserv Dec 09 '14 at 03:35
  • @garethTheRed - the errors you'll usually run into with $((${expansion} +?op)) are related to the expansion's value not making any sense in that context - particularly if a var is empty. You did x=$(($x+1)) - probably on an unset x and probably hit an expecting operator error or something becuase it was just x=$((+1)). Still, in the process you set the value - likely to zero - and so it worked the second time as x=$((0+1)). in most cases you can just do : "$((x+=1))" and save worrying about it. – mikeserv Dec 09 '14 at 05:47
7

Use Brace-Expansion Ranges

Other answers may address how to debug your script. This answer shows you a simpler (and less error-prone) way to do what you want using Bash's brace-expansion to generate a range instead of an incrementing loop.

For example, to print the numbers 1 through 50 using this notation, you can use the following snippet:

for x in {1..50}; do
    echo $x
done 

This will correctly print each number in sequence, but relies on features of Bash that aren't portable across shells. If you need portability, consider using seq instead.

CodeGnome
  • 7,820
3

There is software called BASH debugger and other software will be shellcheck which will give you general errors but not all.

In your script in line 5 use square brackets:

x=$[ $x + 1 ]

Update

Or

x=$(( $x + 1 ))

former one is depricated, better use latter one. Don't use $ before x which comes before = sign

Alex Jones
  • 6,353
2

From your other question about rounding decimals, I see that you want to do this only in bash. So apart from the other answers, you can do it this way too.

#!/bin/bash
x=1
while [[ $x -le 50 ]]
do
    echo $x
    x=$(expr $x + 1)
done
Sreeraj
  • 5,062
2

On systems with the jot command (BSD systems):

jot 50
Kusalananda
  • 333,661
1

Bash like ksh and possibly some other shells natively supports arithmetic loops:

for ((x=1;x<=50;x++)); do
    echo $x
done
jlliagre
  • 61,204
0
#!/bin/bash
for i in $(seq 1 50)
do
echo $i
done

edit: sorry for posting my answer without reading the tour guide and thanks Stephen Kitt to edit my answer.

So in this script, I get the output of seq 1 50 with command substitution $() and iterate that output(sequence of numbers from 1 to 50) with for, and print every i in that sequence with echo $i

And just because you try to print the numbers with loop, I implement it with loop. seq 1 50 or echo {1..50} will give those numbers too, without using iteration.

mirkancal
  • 133
  • 2
    Welcome to Unix.SE! Please take a moment to look at the [tour], and [edit] your answer to explain how its specifics (especially compared to the other answers). Also consider how this is different from a plain seq 1 50 (instead of the loop). – Stephen Kitt Mar 23 '18 at 08:30