Bash Script Countdown Timer: 5-Minute Display with Real-Time Single-Line Updates


2 views

When implementing a countdown timer in Bash, we need three key features:

  • Accurate time calculation (5 minutes = 300 seconds)
  • Single-line display that updates in-place
  • Precise 1-second intervals for updates

Here's the complete implementation that handles all requirements:

#!/bin/bash
countdown() {
    seconds=$1
    while [ $seconds -gt 0 ]; do
        printf "\rCountdown: %02d:%02d" $((seconds/60)) $((seconds%60))
        sleep 1
        ((seconds--))
    done
    echo
}

countdown 300  # 5 minutes = 300 seconds

The magic happens with these techniques:

printf "\rCountdown: %02d:%02d"  # \r returns cursor to line start
sleep 1                          # Precise timing
((seconds--))                    # Arithmetic decrement

For production use, consider these enhancements:

#!/bin/bash
countdown() {
    trap 'echo -e "\nTimer interrupted"; exit' INT
    seconds=$1
    while [ $seconds -gt 0 ]; do
        printf "\r\033[KCountdown: %02d:%02d" $((seconds/60)) $((seconds%60))
        read -t 1 -n 1 && break
        ((seconds--))
    done
    echo -e "\nTimer completed"
}

countdown 300
  • Flickering display: Use \033[K to clear to end of line
  • Keyboard interrupts: Trap SIGINT for clean exits
  • Early termination: Add read -t for user breaks

For maximum compatibility:

printf "\rCountdown: %02d:%02d" $(($seconds/60)) $(($seconds%60))

When working with Bash scripts, sometimes we need to create timers that update in real-time without cluttering the terminal output. The key requirements for this task are:


1. Accurate 5-minute (300-second) countdown
2. Updates every second
3. Output remains on a single line
4. Clean visual display

The most efficient approach combines printf with carriage returns (\r) to overwrite the current line:

#!/bin/bash

duration=300  # 5 minutes in seconds
end_time=$(( $(date +%s) + duration ))

while [ $(date +%s) -lt $end_time ]; do
    remaining=$(( end_time - $(date +%s) ))
    printf "\rCountdown: %02d:%02d" $((remaining/60)) $((remaining%60))
    sleep 1
done
echo -e "\nTime's up!"

For better visualization, we can add a progress bar:

#!/bin/bash

duration=300
end_time=$(( $(date +%s) + duration ))
total_width=50

while [ $(date +%s) -lt $end_time ]; do
    remaining=$(( end_time - $(date +%s) ))
    minutes=$((remaining/60))
    seconds=$((remaining%60))
    progress=$(( (duration - remaining) * total_width / duration ))
    
    printf "\r[%-${total_width}s] %02d:%02d" \
        $(printf "%${progress}s" | tr ' ' '#') \
        $minutes $seconds
    sleep 1
done
echo -e "\n\nTimer complete!"

For more robust scripts that handle terminal resizing:

#!/bin/bash

duration=300
end_time=$(( $(date +%s) + duration ))

cleanup() {
    tput cnorm  # Show cursor
    exit 0
}
trap cleanup EXIT INT
tput civis  # Hide cursor

while [ $(date +%s) -lt $end_time ]; do
    cols=$(tput cols)
    remaining=$(( end_time - $(date +%s) ))
    minutes=$((remaining/60))
    seconds=$((remaining%60))
    
    # Dynamic formatting based on terminal width
    if [ $cols -gt 40 ]; then
        printf "\rTime remaining: %02d minutes %02d seconds " $minutes $seconds
    else
        printf "\r%02d:%02d " $minutes $seconds
    fi
    sleep 1
done

printf "\rTime's up!          \n"
tput cnorm

For more terminal control:

#!/bin/bash

duration=300
end_time=$(( $(date +%s) + duration ))

while [ $(date +%s) -lt $end_time ]; do
    remaining=$(( end_time - $(date +%s) ))
    tput sc  # Save cursor position
    tput cuu1  # Move up one line
    tput el  # Clear to end of line
    printf "%02d:%02d" $((remaining/60)) $((remaining%60))
    tput rc  # Restore cursor position
    sleep 1
done
echo