3

I'm working in BASH and I'm having an idiot moment right now. I've got a project I'm working on that I'm going to need to use some very basic arithmetic expressions and I just realized that a lot of my problems with it are because my variables are not updating. So I threw together a basic algorithm that increments a variable by another variable with a while loop until a certain number is reached.

counter=1
counter2=0

while [[ counter2 < 10 ]]; do
   counter2=$(($counter2+$counter))
   echo $counter
   echo $counter2
done 

I run the script. Does nothing. I set the < to > just for kicks and an infinite loop occurs with a repeated output of:

1
0
1
0

Forever and ever until I stop it. So it's obvious the variables are not changing. Why? I feel like such an idiot because it must be something stupid I'm overlooking. And why, when I have <, it also isn't an infinite loop? Why doesn't it print anything at all for that matter? If counter2 is always less than 10, why doesn't it just keep going on forever?

Thanks folks in advance.

EDIT: Well, I realize why it wasn't outputting anything for when the check is <... I should have been using $counter2 instead of just counter2 to get the actual value of counter2. But now it just outputs:

1
2

And that's it... I feel like such a derp.

RedMageKnight
  • 187
  • 2
  • 12

3 Answers3

4

Inside the $((...)), don't use the sigil ($).

counter2=$((counter2+counter))
Kevin
  • 53,822
  • 15
  • 101
  • 132
  • You need the sigil before the parenthesis, otherwise it complains that it needs the token. Or rather, it complains that '(' is an unexpected token, and everything gets funky. – RedMageKnight Apr 10 '12 at 01:55
  • Yes, before the parens, not inside. – Kevin Apr 10 '12 at 01:56
  • Ah, okay - well, I've done that and it still only goes up to 2 for counter2 >.> I just don't get what I could be missing. – RedMageKnight Apr 10 '12 at 02:01
  • Only before the parens, if this is a standalone expression. If it is a compound expression (`while`, `for`, `if`) you must *not* use the `$` either. Also, wasn't there some issue with `while` and setting variables and then seeing the result after the loop? – 0xC0000022L Apr 10 '12 at 02:14
  • 1
    @STATUS_ACCESS_DENIED, that issue you mention occurs when the while loop is part of a pipeline. In that case, the loop is run in a subshell and changes to variables will be lost when the subshell ends. There's no pipeline here. – glenn jackman Apr 10 '12 at 10:44
4

If this is all bash (100% sure) then you could use declare -i in order to explicitly set type of your variables and then your code will be as simple as :

declare -i counter=1
declare -i counter2=0

while [[ $counter2 -lt 10 ]]; do
   counter2=$counter2+$counter
   echo $counter
   echo $counter2
done

EDIT: In bash, you can do arithmatic comparison with double paranethesis. So, your while can be written as:

while (($counter2 <  10)) ; do
ring bearer
  • 20,383
  • 7
  • 59
  • 72
  • This does nothing either, all it outputs are results up to 2 for `counter2`. So my output roughly looks exactly like what I posted after my edit :/ – RedMageKnight Apr 10 '12 at 01:59
  • No, try now. I edited the script. I did not test my first post. Your condition check needs to be changed too. – ring bearer Apr 10 '12 at 02:00
  • That - that worked >.> I thought that when you used double brackets, you could start using the physical symbols instead of the acronyms for things like 'less than' and 'greater than'. When can you use the symbols then? O.o – RedMageKnight Apr 10 '12 at 02:04
  • And I thought you didn't have to explicitly declare variable types like you do with other conventional programming languages in BASH? – RedMageKnight Apr 10 '12 at 02:06
  • No, you don't have to - if you take care of rest of coding with out confusion. But it is a convenience when are 100% sure about the shell. Edited post about comparison operators. – ring bearer Apr 10 '12 at 02:07
  • Thank you ring bearer - you've cleared up a lot of things for me today :) – RedMageKnight Apr 10 '12 at 02:21
1

In bash, you can use c-like for loops:

for (( counter2=0; counter2<10; counter2+=counter ))
do
   echo $counter": "$counter2
done

Often you will find this construct more appealing to use:

for counter2 in {0..9}
do
    echo $counter": "$counter2
done
user unknown
  • 35,537
  • 11
  • 75
  • 121