Ralph
Ralph

Reputation: 3029

Why is this bash program going into an infinite loop?

#!/bin/bash

echo "Enter number of loops"
read count
echo $count
if [ $count -eq 0 ]
 then
    echo "The count cannot be zero. Enter a number again"
    read count
fi

while [ $count -gt 0 ]
do
    echo "Loop numner $count"
    count = `expr $count - 1`
done

I am trying to simulate a Java counter in bash. Does this exist?

Upvotes: 1

Views: 189

Answers (3)

gniourf_gniourf
gniourf_gniourf

Reputation: 46823

Here's a rock solid rewriting of your script, to show you how it's usually done:

#!/bin/bash

while true; do
    read -rep "Enter number of loops: " count
    if [[ $count = +([[:digit:]]) ]]; then
        ((count=10#$count))
        ((count>0)) && break
        printf 'The count cannot be zero. Enter a number again.\n'
     else
        printf 'Please enter a valid number.\n'
     fi
done

while ((count>0)); do
    printf 'Loop number %s\n' "$count"
    ((--count))
done
  • Using read with the -r flag to have backslashes not escape some characters (this should be the default), with the -e option so that read uses readline: it's more comfortable for the user, and with the -p option to specify the prompt.
  • I completely revisited the logic you're using to read user's input: read is run in an infinite loop that can only be broken when user enters a valid number. With your method, a user could enter invalid data twice, and the loop would have run with random arguments. Not good.
  • To check that user input is valid, I'm using pattern matching: [[ $count = +([[:digit:]]) ]] that is true if and only if count expands to a string of one or more digits, then I'm making sure that Bash will treat count in radix 10: in arithmetic context, 10#$count treats count in radix 10. Without this, an input like 08 or 09 would make some subsequent parts fail, as a leading zero means, for Bash, that the number should be interpreted in radix 8, hence 08 is not valid!
  • The final loop is written with Bash's arithmetic context ((...)). You don't need the external expr to perform simple arithmetic.

Upvotes: 3

asimovwasright
asimovwasright

Reputation: 838

You can also use bash arithmetic expansion:

    count="$((count -1))"

I would also suggest making the first test -le not -eq, in case the user types in a negative integer, and quote it in case the user types nothing at all.

    if [ "$count" -le 0 ]

So your code would be:

    #!/bin/bash

    echo "Enter number of loops"
    read count
    echo $count
    if [ "$count" -le 0 ]
     then
        echo "The count cannot be zero. Enter a number again"
        read count
    fi

    while [ $count -gt 0 ]
    do
        echo "Loop numner $count"
        count="$((count - 1))"
    done

Upvotes: 0

SMA
SMA

Reputation: 37023

You have space in between your assignment statement as below:

count = `expr $count - 1`
     ^  ^

Remove the space between "=" like below:

count=`expr $count - 1`
Output
Enter number of loops
10
10
Loop numner 10
Loop numner 9
Loop numner 8
Loop numner 7
Loop numner 6
Loop numner 5
Loop numner 4
Loop numner 3
Loop numner 2
Loop numner 1

Note apart, backticks are discouraged and you should be using something like:

 count=$(expr $count - 1)

Upvotes: 5

Related Questions