Problem when trying a simple loop in bash

#!bin/sh
a=0
while["$a -lt 50"]
do
echo $a
a='expr $a+1'
done

I get infinite echos of expr $a+1. what am I doing wrong?

Answer

Your script has syntax errors. You may check shell scripts for problematic constructs using ShellCheck on-line.

This will tell you

Line 3:
while["$a -lt 50"]
^-- SC1009: The mentioned parser error was in this while loop.
     ^-- SC1035: You need a space after the [ and before the ].
     ^-- SC1069: You need a space before the [.
     ^-- SC1073: Couldn't parse this test expression.
                  ^-- SC1020: You need a space before the ].
                  ^-- SC1072: Missing space before ]. Fix any mentioned problems and try again.

Fixing space issues by changing

while["$a -lt 50"]

into

while [ "$a -lt 50" ]

will instead give you the following:

Line 3:
while [ "$a -lt 50" ]
           ^-- SC2157: Argument to implicit -n is always true due to literal strings.

Line 6:
a='expr $a+1'
  ^-- SC2016: Expressions don't expand in single quotes, use double quotes for that.

The first issue reported is about the string "$a -lt 50". In fact, you don’t want to have a string like that here, you want "$a" -lt 50. By the way, since a string is always “true”, this is why your loop is infinite (if the syntax errors are fixed).

The second issue is due to the checker detecting the variable $a inside a singly quoted string, where it wouldn’t be expanded to its value (and this is why the string printed is expr $a+1). The solution is not to change it to double quotes as that would just give you the same string but with the value expanded. You want to execute the expr command.

Do that by changing you single quotes to back-ticks.

Your script now looks like this:

#!bin/sh
a=0
while [ "$a" -lt 50 ]
do
echo $a
a=`expr $a+1`
done

… and ShellCheck is still not happy:

Line 6:
a=`expr $a+1`
  ^-- SC2006: Use $(..) instead of legacy `..`.
   ^-- SC2003: expr is antiquated. Consider rewriting this using $((..)), ${} or [[ ]].

New shell code should really use $( ... ) rather than back-ticks. Also, it gives you a warning about your use of expr, which is outdated.

The line may be rewritten as

a="$(( a + 1 ))"

The final version (plus indentation and a fix to the #!-line):

#!/bin/sh

a=0
while [ "$a" -lt 50 ]; do
  echo $a
  a="$(( a + 1 ))"
done

bash or ksh93 version using (( ... )) for arithmetic evaluation, and with further shortening of the code:

#!/bin/bash

a=0
while (( a < 50 )); do
  echo "$(( a++ ))"
done

Leave a Reply

Your email address will not be published. Required fields are marked *