29

I would like to have a count down of 5 minutes, updating every second and showing the result on the same line. Is this even possible with Bash scripting?

ptheofan
  • 411
  • 1
  • 4
  • 6
  • What does the countdown do? You need to be a little more specific about the whole thing. – Adrian Frühwirth Aug 21 '13 at 09:41
  • This is absolutely possible. If you tell us why (what actual system/network administration problem you're trying to solve) we can tell you which of the many available methods to do it will likely work best for you. If it's a general "How do I do this in a `bash` script?` question your question is probably better suited to [unix.se] -- let me know and I can migrate it there for you :) – voretaq7 Aug 21 '13 at 14:04
  • Here's a way https://github.com/himanshub16/MyScripts/blob/master/countdown.sh – Himanshu Shekhar Jun 01 '16 at 19:13

2 Answers2

59

This works from Bash shell:

secs=$((5 * 60))
while [ $secs -gt 0 ]; do
   echo -ne "$secs\033[0K\r"
   sleep 1
   : $((secs--))
done

The special character \033[0K represents an end of line which cleans the rest of line if there are any characters left from previous output and \r is a carriage return which moves the cursor to the beginning of the line. There is a nice thread about this feature at stackoverflow.com.

You can add own commands or whatever in the while loop. If you need something more specific please provide me more details.

dsmsk80
  • 5,817
  • 18
  • 22
  • Do you mean \033[K as per http://ascii-table.com/ansi-escape-sequences.php instead of 0K? – Jody Bruchon Oct 04 '15 at 00:04
  • I put `\r` at the beginning to put cursor at the end of line (which prevent it to hide the first character). Here is the updated version: https://gist.github.com/boillodmanuel/676b3af823fae4177f1d0b41a6f23442 Thanks – user1067920 Nov 08 '19 at 10:11
  • 1
    Note for anyone confused by the leading colon on line 5: That is the null operator, allowing the following `$((...))` construction to be evaluated without being interpreted as a command. However, I believe the same effect can be had more simply by just putting `((secs--))` in place of `: $((secs--))`. – shawkinaw Jan 13 '20 at 15:33
  • arithmetic expression: expecting primary: "secs--" – Aadam Jan 02 '22 at 21:40
15

Here's one with an improvement of right output format (HH:MM:SS) with proper leading zeros and supporting hours:

#!/bin/bash

m=${1}-1 # add minus 1 

Floor () {
  DIVIDEND=${1}
  DIVISOR=${2}
  RESULT=$(( ( ${DIVIDEND} - ( ${DIVIDEND} % ${DIVISOR}) )/${DIVISOR} ))
  echo ${RESULT}
}

Timecount(){
        s=${1}
        HOUR=$( Floor ${s} 60/60 )
        s=$((${s}-(60*60*${HOUR})))
        MIN=$( Floor ${s} 60 )
        SEC=$((${s}-60*${MIN}))
     while [ $HOUR -ge 0 ]; do
        while [ $MIN -ge 0 ]; do
                while [ $SEC -ge 0 ]; do
                        printf "%02d:%02d:%02d\033[0K\r" $HOUR $MIN $SEC
                        SEC=$((SEC-1))
                        sleep 1
                done
                SEC=59
                MIN=$((MIN-1))
        done
        MIN=59
        HOUR=$((HOUR-1))
     done
}

Timecount $m

Gives an output that looks like this:

02:04:15
user1855221
  • 103
  • 2
rahuL
  • 692
  • 3
  • 12
  • 31