Q: I am writing a Linux bash script that opens a port for two hours and then closes it.  I use sleep 7200 to make it wait two hours before closing the port.  This works fine, but when I walk away it is hard for me to know when the port will be closed.  I wanted to make a countdown timer to show how much longer the script will take to run.  I found some code on the net but couldn't get any of them to work for me.

A: I am sure there are plenty of ways to make a countdown, but here is what I came up with. Just using some while loops I was able to create a simple countdown timer. In the second section I commented the code to help you understand what each line does.

Simple Bash Countdown Timer

You can change the hour, minute (min), or second (sec) variable to change how long the timer runs.

#!/bin/bash
hour=0
min=0
sec=10
while [ $hour -ge 0 ]; do
while [ $min -ge 0 ]; do
while [ $sec -ge 0 ]; do
echo -ne "$hour:$min:$sec\033[0K\r"
let "sec=sec-1"
sleep 1
done
sec=59
let "min=min-1"
done
min=59
let "hour=hour-1"
done

Here is a video of the timer in action.

Here is the code commented above each line to explain how it works:

#!/bin/bash
# Set variables to your desired time.
hour=2
min=0
sec=0
       # begin hour while loop - while hour
       #variable is greater than or equal to 0 do minute loop
while [ $hour -ge 0 ]; do
                # begin minute loop - while min variable
                #is greater than or equal to 0 do second loop
                while [ $min -ge 0 ]; do
                        # begin second loop - while sec variable is greater
                        # than or equal to 0 print time left
                        while [ $sec -ge 0 ]; do
                                # echo time on same line so it overwrites last                                             # line, makes it look like countdown
                                echo -ne "$hour:$min:$sec\33[0Kr"
                                # Decrease the sec variable by 1
                                #each iteration of loop to countdown
                                let "sec=sec-1"
                                # wait a second before removing a second
                                # from the countdown clock
                                sleep 1
                        # End second loop
                        done
                        # Set second timer back to 59 to start new minute
                        sec=59
                        # Decrease min variable by 1 to remove a
                        # minute off the countdown
                        let "min=min-1"
                # end minute loop
                done
                # Set minute timer back to 59 to start new hour
                min=59
                # decrease the hour by 1 to remove hour off the countdown
                let "hour=hour-1"
        # end hour loop
        done 

Bash Countdown Timer with Colored Text

If you want to get a little fancier, we can add some color to our bash script. The code below will check to see if the timer reached under a minute, and if so turn the color of the font yellow. When the timer gets to 10 seconds, it turns it red. The tput command is used to hide the cursor to refine it further. I also incorporated the printf statement left in the comments by one of our readers. This adds leading zeros where appropriate.

#!/bin/bash
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
RESET='\033[0m'
hour=0
min=1
sec=11
tput civis
echo -ne "${GREEN}"
while [ $hour -ge 0 ]; do
while [ $min -ge 0 ]; do
while [ $sec -ge 0 ]; do
if [ "$hour" -eq "0" ] && [ "$min" -eq "0" ]; then
echo -ne "${YELLOW}"
fi
if [ "$hour" -eq "0" ] && [ "$min" -eq "0" ] && [ "$sec" -le "10" ]; then
echo -ne "${RED}"
fi
echo -ne "$(printf "%02d" $hour):$(printf "%02d" $min):$(printf "%02d" $sec)\033[0K\r"
let "sec=sec-1"
sleep 1
done
sec=59
let "min=min-1"
done
min=59
let "hour=hour-1"
done
echo -e "${RESET}"
tput cnorm

Bash Countdown Timer Using tput for Screen Painting

Here is another example, this time using tput to color the screen yellow for warning and red for the last ten seconds. Code to follow.

Here is the code for the countdown timer above.

#!/bin/bash
Set Variables
cols=$( tput cols )
rows=$( tput lines )
middle_row=$(( $rows / 2 ))
middle_col=$(( ($cols /2) - 4 ))
hour=0
min=1
sec=12

donso () {
tput sgr0
tput cup $( tput lines ) 0
tput cnorm
}

tput clear
tput bold
tput civis
while [ $hour -ge 0 ]; do
while [ $min -ge 0 ]; do
while [ $sec -ge 0 ]; do
if [ "$hour" -eq "0" ] && [ "$min" -eq "0" ]; then
tput setab 3
tput clear
fi
if [ "$hour" -eq "0" ] && [ "$min" -eq "0" ] && [ "$sec" -le "10" ]; then
tput setab 1
tput clear
fi
tput cup $middle_row $middle_col
echo -ne "$(printf %02d:%02d:%02d $hour $min $sec)\e"
let "sec=sec-1"
sleep 1
done
sec=59
let "min=min-1"
done
min=59
let "hour=hour-1"
done
echo -e "${RESET}"
donso