Bash PS1 Prompt – Show Elapsed Time

bashprompt

I currently use this to display the current time in my bash prompt:

PS1=\[\e[0;32m\]\t \W>\[\e[1;37m\]

20:42:23 ~>

Is it possible to display the elapsed time since the previous prompt?
Such as:

00:00:00 ~> sleep 10
00:00:10 ~> sleep 20
00:00:20 ~>

This has nothing in common with Is it possible to change the PS1 periodically by a script in the background?

Best Answer

One way to do it would be to use the PROMPT_COMMAND feature of bash to execute code that modifies PS1. The function below is an updated version of my original submission; this one uses two fewer environment variables and prefixes them with "_PS1_" to try to avoid clobbering existing variables.

prompt_command() {
  _PS1_now=$(date +%s)
  PS1=$( printf "\[\e[0;32m\]%02d:%02d:%02d \W>\[\e[1;37m\] " \
           $((  ( _PS1_now - _PS1_lastcmd ) / 3600))         \
           $(( (( _PS1_now - _PS1_lastcmd ) % 3600) / 60 )) \
           $((  ( _PS1_now - _PS1_lastcmd ) % 60))           \
       )
  _PS1_lastcmd=$_PS1_now
}
PROMPT_COMMAND='prompt_command'
_PS1_lastcmd=$(date +%s)

Put that into your .bash_profile to get things started up.

Note that you have to type pretty quickly to get the sleep parameter to match the prompt parameter -- the time really is the difference between prompts, including the time it takes you to type the command.

00:00:02 ~> sleep 5   ## here I typed really quickly
00:00:05 ~> sleep 3   ## here I took about 2 seconds to enter the command
00:00:10 ~> sleep 30 ## more slow typing
00:01:35 ~>

Late addition:

Based on @Cyrus' now-deleted answer, here is a version that does not clutter the environment with extra variables:

PROMPT_COMMAND='
    _prompt(){
        PROMPT_COMMAND="${PROMPT_COMMAND%-*}-$SECONDS))\""
        printf -v PS1 "\[\e[0;32m\]%02d:%02d:%02d \W>\[\e[1;37m\] " \
                      "$(($1/3600))" "$((($1%3600)/60))" "$(($1%60))"
    }; _prompt "$((SECONDS'"-$SECONDS))\""

Extra late addition:

Starting in bash version 4.2 (echo $BASH_VERSION), you can avoid the external date calls with a new printf format string; replace the $(date +%s) pieces with $(printf '%(%s)T' -1). Starting in version 4.3, you can omit the -1 parameter to rely on the "no argument means now" behavior.

Related Question