2

I found here on superuser the following nice countdown script that I could include in my .bash_profile:

function countdown(){  
   date1=$((`date +%s` + $1));   
   while [ "$date1" -ne `date +%s` ]; do   
     echo -ne "$(date -u --date @$(($date1 - `date +%s`)) +%H:%M:%S)\r";  
     sleep 0.1  
  done  
}

It doesn't work on OSX, i understand, because of the differences in the date command. Another user commented as such but the problem remained unresolved in that question.

The same problem (I think) is also discussed and solved here but I cannot work out how to modify the countdown script to utilise this solution.

4

Personally, I'd refactor that a bit for readability (still relying on GNU date)

function countdown(){  
    local now=$(date +%s)
    local end=$((now + $1))
    while (( now < end )); do   
        printf "%s\r" "$(date -u -d @$((end - now)) +%T)"  
        sleep 0.25  
        now=$(date +%s)
    done  
    echo
}

Mapping the date calls to OSX's BSD date (man page here)

It looks like the GNU date invocation

date -u -d @$((end - now)) +%T

translates to this BSD date invocation

date -u -j -f %s $((end - now)) +%T

but that's untested.

7
  • Bash is returning an unexpected EOF error on the printf line. – Tim Dec 9 '14 at 16:37
  • Are you sure you have all the quotes matching. The code I posted works (with bash version 4 at any rate) – glenn jackman Dec 9 '14 at 17:23
  • my fault: one of my double quotes was curly (damn autocorrect....) The code works perfectly now. – Tim Dec 10 '14 at 13:48
  • Time to pick a better editor. – glenn jackman Dec 10 '14 at 14:45
  • 1
    You could add if (( $# <1 )); then return; fi as the first line for a bit of robustness. – Burhan Ali Feb 2 '19 at 9:45
1

I tried @glenn's answer on macOS Mojave in Bash and Zsh, and it worked well. The last echo in his code near the last line might not be needed:

function countdown() {  
    local now=$(date +%s)
    local end=$((now + $1))
    while (( now < end )); do   
        printf "%s\r" "$(date -u -j -f %s $((end - now)) +%T)"  
        sleep 0.25  
        now=$(date +%s)
    done  
}

and to count down:

countdown 30                       # for 30 seconds
countdown $((10*60))               # 10 minutes
countdown $((1*60*60 + 30*60))     # 1 hour 30 minutes

I am not so familiar with shell scripts, so perhaps somebody could add a display for number of days if the countdown is more than a day.

To give an audio bell at the end of the countdown, add an extra line near the end:

function countdown() {  
    local now=$(date +%s)
    local end=$((now + $1))
    while (( now < end )); do   
        printf "%s\r" "$(date -u -j -f %s $((end - now)) +%T)"  
        sleep 0.25  
        now=$(date +%s)
    done  
    echo -en "\a"
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.