Bash Prompt with Execution Timer

Bash Prompt Index

The $PS1 string in Bash is used to set the Bash prompt. There are other prompt strings are $PS2, $PS3, $PS4, and more recently $PS0 has been added. $PS0 is "expanded and displayed by interactive shells after reading a command and before the command is executed." It's executed BEFORE the command, and $PS1 is executed after, making it possible to capture the amount of time taken by the executed command.

(This isn't the first time this has been done - but most of the methods I've seen to achieve this were awkward, or at best used something like Perl to do the work. I wanted a pure Bash solution. It's not elegant, but it works ...)

(( threshold = 5 ))

YELLOW='\033[1;33m'
PURPLE='\033[1;35m'
NOCOLOUR='\033[0m'

if ! [ -d "${HOME}/tmp" ]
then
    mkdir "${HOME}/tmp"
fi
timestamp="${HOME}/tmp/.prompt_datestamp.$$"

# Create this immediately or the prompt barfs on first run:
date "+%s" > "${timestamp}"

PS0="\$(
    date \"+%s\" > \"${timestamp}\"
)"
export PS0

PS1="${PURPLE}"
PS1+="\$(
    elapsedSeconds=\$(( \$(date \"+%s\") - \$(cat \"${timestamp}\") ))
    if (( \${elapsedSeconds} > ${threshold} ))
    then
        echo \"\${elapsedSeconds} seconds \"
    fi
    date \"+%s\" > \"${timestamp}\"
)"
PS1+="${YELLOW}"
PS1+="\w\n\!\\\$${NOCOLOUR} "
export PS1

Notice that this writes to a file to save the timestamp - repeatedly. Which sucks. But here's the problem: to execute code (the storing and retrieval of the timestamp) in the $PS? environment variables, we use command substitution, code contained inside $( and ). Reading an environment variable from a parent shell usually works - although not always, and it shouldn't be trusted because it can be overlaid by a variable of the same name in the subshell. But writing an environment variable to a parent shell doesn't work, end of story. So we use a file.

screenshot: the timer prompt in action

prompt with timer.  Short-running commands don't indicate how long they took, longer commands (including a session in an editor) show how many seconds elapsed.

Notice that an editor session (I use nvim, the NeoVim editor) also shows how long we were in the editor. I had hoped to control this behaviour by creating either an ignore-list (nvim and other editors being the obvious first addition) or an include-list (with things like make, mv, cp and dd being at the top of my list here) - but to do either of these things, you have to know what the executed command is. If anyone can clue me in on how to do this, I'd be happy to hear it. But don't assume that any of the commands you know for listing the last command will work: inside command substitutions in the PS? strings, none that I can think of work as expected.