How do I create a stopwatch Bash script to constantly display elapsed time? How do I create a stopwatch Bash script to constantly display elapsed time? bash bash

How do I create a stopwatch Bash script to constantly display elapsed time?


I use the following code snippet in long-running scripts.The timer runs in a function (separate process) which will be killed (trap) if the main process is terminated by a keybord interrupt. The output shows the time elapsed from the start of the timer:

... working [hh:mm:ss]  00:07:58

The snippet:

#===  FUNCTION  ================================================================#          NAME:  progressIndicatorTime#   DESCRIPTION:  Display a progress indicator with seconds passed.#    PARAMETERS:  [increment]   between 1 and 60 [sec], default is 2 [sec]#===============================================================================function progressIndicatorTime (){  declare default=2                                       # default increment [sec]  declare increment="${1:-$default}"                      # 1. parameter or default  declare format='\b\b\b\b\b\b\b\b%02d:%02d:%02d'         # time format hh:mm:ss  declare timepassed=0  declare seconds minutes hours  [[ ! "$increment" =~ ^([1-9]|[1-5][0-9]|60)$ ]] && increment=$default  printf " ... working [hh:mm:ss]  00:00:00"  while : ; do                                            # infinite loop     ((seconds=timepassed%60))    ((minutes=timepassed/60))    ((hours=minutes/60))    ((minutes=minutes%60))    printf "$format" $hours $minutes $seconds    sleep $increment || break                             # sleep ...    ((timepassed+=increment))  done}    # ----------  end of function progressIndicatorTime  ----------progressIndicatorTime &                                   # run progress indicatordeclare progressIndicatorPid=${!}                         # save process IDtrap  "kill $progressIndicatorPid" INT TERM               # trap keyboard interrupt## run long command#kill -s SIGTERM $progressIndicatorPid                     # terminate progress indicator


The art could use some work, but give this a try:

#!/bin/bashref_date='Thu Apr 19 17:07:39 CDT 2012'ref_sec=$(date -j -f '%a %b %d %T %Z %Y' "${ref_date}" +%s)update_inc=1tput clearcat <<'EOF'            [|]     [|]         _-'''''''''''''-_        /                 \       |                   |       |                   |       |                   |        \                 /         '-_____________-'EOFwhile :do  ((sec=$(date +%s) - ${ref_sec}))  ((day=sec/86400))  ((sec-=day*86400))  ((hour=sec/3600))  ((sec-=hour*3600))  ((min=sec/60))  ((sec-=min*60))  tput cup 6 14  printf "%.2id:%.2ih:%.2im:%.2is\r" ${day} ${hour} ${min} ${sec}  sleep ${update_inc}doneexit 0

Note that the syntax of the first date command is for OSX.

For GNU date, use date --date="${ref_date}" +%s


If you have Bash4 or ksh93, you can use the printf %()T syntax to print strftime formats. The following example is Bash 4 printing in the format you want. Bash precision is limited to 1 second. ksh93 supports floats and would require some modification.

#!/usr/bin/env bash# To supply a default date/time. To use now as the default, leave empty, or run with a null first arg.deftime='Fri Apr 14 14:00:00 EDT 2011'if (( ${BASH_VERSINFO[0]}${BASH_VERSINFO[1]} >= 42 )); then    unixTime() {        printf ${2+-v "$2"} '%(%s)T' -1    }else    unixTime() {        printf ${2+-v "$2"} "$(date '+%s')"    }fistopWatch() {    local timestamp="$(date ${1:+'-d' "$1"} '+%s')" curtime day=$((60*60*24)) hour=$((60**2))    # unixTime -1 timestamp    while        unixTime -1 curtime        (( curtime -= timestamp ))        printf '%02dd:%02dh:%02dm:%02ds\r' $(( curtime / day )) $(( (curtime / hour) % 24 )) $(( (curtime / 60) % 60 )) $(( curtime % 60 ))        do sleep 1    done}stopWatch "${1-deftime}"

You may also be interested in the $SECONDS variable. Unfortunately there is no convienient way to accept a human-readable date like you want. It would require considerable parsing effort. The date command (particularly GNU date) can do that to a limited extent.