4
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?

  • Use bash -x scriptname to debug. – jherran Dec 8 '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 8 '14 at 11:52
  • 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 8 '14 at 11:55
  • 1
    Thanks, @muru I started 10 mins back. thinking of doing it in normal way first. – WannaBeCoder Dec 8 '14 at 11:57
  • 1
    @WannaBeCoder you are using let and could also just do ((x++)). Also look up the let command. – user78605 Dec 8 '14 at 12:01
8

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 8 '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 8 '14 at 12:38
  • 1
    @StéphaneChazelas the question is tagged bash. Does it matter what happens elsewhere? – muru Dec 8 '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 8 '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 8 '14 at 12:48
12

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 8 '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. – Patrick Dec 8 '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 8 '14 at 12:36
  • 1
    @HalosGhost Perhaps Stephane prefers recursion to iteration. :) – muru Dec 8 '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 8 '14 at 12:41
5

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.

  • Beware that seq is not portable either not being part of the POSIX specified utilities. – jlliagre Dec 8 '14 at 23:21
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

  • 3
    Just so you know, even though the TLDP Bash beginner's guide recommends this syntax, it is deprecated. – muru Dec 8 '14 at 12:10
2

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}
  • 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
1

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
1

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

for ((x=1;x<=50;x++)); do
    echo $x
done
1
#!/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.

  • 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 8:30
0

On systems with the jot command (BSD systems):

jot 50

protected by Kusalananda Mar 23 '18 at 10:22

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.