3

I have a script named build_other:

count=0
while [ $count -lt 6 ]
do
    ./build
    count+=1
done

From this script, you can see I am calling a second script, named build:

echo "building job"
sleep 30s
echo "wake after sleep"
echo "file build" >> output.txt

I expect that build should be triggered 5 times, because count increases by 1 after build runs. This means output.txt should have 5 lines saying file build. The following is the output I actually received.

building job
wake after sleep
building job
wake after sleep

The file output.txt has only two lines in it.

file build
file build

Why is the loop not running 5 times as I expected?

1
  • Rerun your script with declare -i count=0 and see Dan's Answer below for the complete explanation. Commented Dec 11, 2015 at 20:28

1 Answer 1

3

The += operator does not do what you think here; it is not an "add to" operator, it is acting as a string concatenation operator.

$ ./foo.sh
./build
count is now 01
./build
count is now 011

After two iterations, count is 011. Using the numeric less-than operator -lt, the string 011 is converted to the numeric 11. Since 11 is not less than 6, the loop ends.

Assuming you are using bash or another modern Bourne-family shell, you can solve this in a few ways.

# Using arithmetic expansion -- $(( expression ))
count=$((count + 1))

# Increment variable in an arithmetic evaluation context -- (( ))
(( count++ ))

# When declaring count, declare that it is an integer value. Declared an
# integer, the += operator will behave as you originally expected it would.
declare -i count=0

A few excerpts from the bash man page are below.

On the behavior of the += operator:

In the context where an assignment statement is assigning a value to a shell variable or array index, the += operator can be used to append to or add to the variable's previous value. When += is applied to a variable for which the integer attribute has been set, value is evaluated as an arithmetic expression and added to the variable's current value, which is also evaluated. When += is applied to an array variable using compound assignment (see Arrays below), the variable's value is not unset (as it is when using =), and new values are appended to the array beginning at one greater than the array's maximum index (for indexed arrays) or added as additional key-value pairs in an associative array. When applied to a string-valued variable, value is expanded and appended to the variable's value.

On arithmetic evaluation:

Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. The format for arithmetic expansion is:

$((expression))

The old format $[expression] is deprecated and will be removed in upcoming versions of bash.

The expression is treated as if it were within double quotes, but a double quote inside the parentheses is not treated specially. All tokens in the expression undergo parameter and variable expansion, command substitution, and quote removal. The result is treated as the arithmetic expression to be evaluated. Arithmetic expansions may be nested.

On arithmetic evaluation context:

((expression))

The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION. If the value of the expression is non-zero, the return status is 0; otherwise the return status is 1. This is exactly equivalent to let "expression".

Sign up to request clarification or add additional context in comments.

3 Comments

Good answer. You may want to mention a couple alternatives to the direct assignment like ((count++)) or simply setting the integer flag on count (e.g. declare -i count=0). Still, it's worth a vote. (also, just a nit, when copying man pages, check for hyphenations (e.g. vari‐ able) to make it read better -- I know they are a pain....)
Good suggestions all; I've included both alternatives, fixed hyphenation, and added some more bash(1) excerpts.
One question three answers and so good explanation Thanks Dan Lowe it solved my problem and the three solution worked out for me

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.