Counting down in a loop to zero by the number being given

17.3k Views Asked by At

I am trying to write a while loop to determine the number is being given to count down to 0. Also, if there's no argument given, must display "no parameters given.

Now I have it counting down but the last number is not being 0 and as it is counting down it starts with the number 1. I mush use a while loop.

My NEW SCRIPT.

 if [ $# -eq "0" ] ;then
       echo "No paramters given"
 else
       echo $#
  fi

 COUNT=$1
 while [ $COUNT -gt 0 ] ;do
         echo $COUNT
         let COUNT=COUNT-1
  done
  echo Finished!

This is what outputs for me.

 sh countdown.sh 5
1
5
4
3
2
1
Finished!

I need it to reach to 0

4

There are 4 best solutions below

3
leu On

Your code is far from being able to run. So, I don't know where to start to explain. Let's take this small script:

#!/bin/sh

die() {
   echo $1 >&2
   exit 1;
}

test -z "$1" && die "no parameters given"
for i in $(seq $1 -1 0); do
   echo "$i"
done

The main part is the routine seq which does what you need: counting from start value to end value (with increment in between). The start value is $1, the parameter to our script, the increment is -1. The test line tests whether there is a parameter on the command line - if not, the script ends via the subroutine die.

Hth.

0
David C. Rankin On

There are a number of ways to do this, but the general approach is to loop from the number given to an ending number decrementing the loop count with each iteration. A C-style for loop works as well as anything. You will adjust the sleep value to get the timing you like. You should also validate the required number and type of input your script takes. One such approach would be:

#!/bin/bash

[ -n "$1" ] || {
    printf " error: insufficient input. usage:  %s number (for countdown)\n" "${0//*\//}"
    exit 1
}

[ "$1" -eq "$1" >/dev/null 2>&1 ] || {
    printf " error: invalid input. number '%s' is not an integer\n" "$1"
    exit 1
}

declare -i cnt=$(($1))

printf "\nLaunch will occur in:\n\n"

for ((i = cnt; i > 0; i--)); do

    printf " %2s\n" "$i"
    sleep .5

done

printf "\nFinished -- blastoff!\n\n"

exit 0

Output

$ bash ./scr/tmp/stack/countdown.sh 10

Launch will occur in:

 10
  9
  8
  7
  6
  5
  4
  3
  2
  1

Finished -- blastoff!

Your Approach

Your approach is fine, but you need to use the value of COUNT $COUNT in your expression. You also should declare -i COUNT=$1 to tell the shell to treat it as an integer:

#!/bin/bash

if [ $# -eq "0" ] ;then
    echo "No paramters given"
else
    echo -e "\nNumber of arguments: $#\n\n"
fi

declare -i COUNT=$1

while [ $COUNT -gt 0 ] ;do
    echo $COUNT
    let COUNT=$COUNT-1
done
echo -e "\nFinished!\n"
1
mklement0 On

@Slizzered has already spotted your problem in a comment:

  • You need operator -ge (greater than or equal) rather than -gt (greater than) in order to count down to 0.
  • As for why 1 is printed first: that's simply due to the echo $# statement before the while loop.

If you're using bash, you could also consider simplifying your code with this idiomatic reformulation:

#!/usr/bin/env bash

# Count is passed as the 1st argument.
# Abort with error message, if not given.
count=${1?No parameters given}

# Count down to 0 using a C-style arithmetic expression inside `((...))`.
# Note: Increment the count first so as to simplify the `while` loop.
(( ++count )) 
while (( --count >= 0 )); do
  echo $count
done

echo 'Finished!'
5
geirha On

You should also validate the variable before using it in an arithmetic context. Otherwise, a user can construct an argument that will cause the script to run in an infinite loop or hit the recursion limit and segfault.

Also, don't use uppercase variable names since you risk overriding special shell variables and environment variables. And don't use [ in bash; prefer the superior [[ and (( constructs.

#!/usr/bin/env bash
shopt -s extglob     # enables extended globs

if (( $# != 1 )); then
    printf >&2 'Missing argument\n' 
    exit 1
elif [[ $1 != +([0-9]) ]]; then
    printf >&2 'Not an acceptable number\n'
    exit 2
fi

for (( i = $1; i >= 0; i-- )); do
    printf '%d\n' "$i"
done

# or if you insist on using while
#i=$1
#while (( i >= 0 )); do
#    printf '%d\n' "$((i--))"
#done