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

14

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.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • 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
10

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нιη
  • 40,939
  • 15
  • 71
  • 114
  • 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.

Mandar Shinde
  • 3,156
  • 11
  • 39
  • 58
  • 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](http://pubs.opengroup.org/onlinepubs/9699919799/) : *...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
  • @mikerserv, see [this](http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9971) as referenced in the [question that spun off that comment](http://unix.stackexchange.com/q/172103/22565) – Stéphane Chazelas Dec 09 '14 at 07:38
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,710
  • 1
  • 18
  • 25
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,223
  • 17
  • 51
  • 83
  • 3
    Just so you know, even though the TLDP Bash beginner's guide recommends this syntax, it is [deprecated](http://stackoverflow.com/questions/2415724/bash-arithmetic-expression-vs-arithmetic-expression). – muru Dec 08 '14 at 12:10
3

On systems with the jot command (BSD systems):

jot 50
Kusalananda
  • 320,670
  • 36
  • 633
  • 936
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
  • 4,984
  • 10
  • 38
  • 57
1

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

for ((x=1;x<=50;x++)); do
    echo $x
done
jlliagre
  • 60,319
  • 10
  • 115
  • 157
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
  • 7
  • 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