Search code examples
shellcountdown

countdown in shell without seq or jot


I'm trying to make a countdown timer script that takes a number of seconds as $1, then counts down to zero, showing the current remaining seconds as it goes.

The catch is, I'm doing this on an embedded box that doesn't have seq or jot, which are the two tools I know can generate my list of numbers.

Here's the script as I have it working on a normal (non-embedded) system:

#!/bin/sh

for i in $(/usr/bin/jot ${1:-10} ${1:-10} 1); do
    printf "\r%s " "$i"
    sleep 1
done

echo ""

This works in FreeBSD. If I'm on a Linux box, I can replace the for line with:

for i in $(/usr/bin/seq ${1:-10} -1 1); do

for the same effect.

But what do I do if I have no jot OR seq?


Solution

  • If your shell was bash, you could count down from a fixed number with something like this:

    #!/bin/bash
    
    for n in {10..1}; do
      printf "\r%s " $n
      sleep 1
    done
    

    But that won't work for you, because bash won't handle things like {${1:-10}..1}, and you've specified you want a command line option. Of course, you've also said you're not using bash, so we'll assume a simpler shell.

    If you have awk, you can use that to count.

    #!/bin/sh
    
    for n in $(awk -v m="${1:-10}" 'BEGIN{for(;m;m--){print m}}'); do
      printf "\r%s " $n
      sleep 1
    done
    printf "\r \r"  # clean up
    

    If you don't have awk, you should be able to do it in pure shell:

    #!/bin/sh
    
    n=${1:-10}
    
    while [ $n -gt 0 ]; do
      printf "\r%s " $n
      sleep 1
      n=$((n-1))
    done
    printf "\r \r"  # clean up
    

    I think the pure-shell version is probably simple enough that it should be preferred over the awk solution.

    Of course, as Mark Reed pointed out in comments, if your system doesn't include a printf, then you'll need to perform some ugly echo magic that will depend on your OS or shell... and if your shell doesn't support $((..)), you can replace that line with n=$(expr $n - 1). If you want to add error handling in case a non-numeric $1 is provided, that wouldn't hurt.