Having fun with the bash prompt
Run Time
I frequently want to know how long a command took, but only after I realize that it's taking longer than I expected. So I modified my bash prompt to time every single command I run. So each prompt looks like
[eli@hostname blog]$ [13]
When a command takes a long time, I may want to go work on something else for a couple of minutes, but still want to know when it completes. So I made the command prompt include a bell character and an exclamation point if the command exceeded 5 seconds.
[eli@hostname blog]$ [13!]
It would also be nice to have my eye drawn to the prompt if it took a long time, but I don't want to be distracted by all the [0]'s getting displayed. So I made the color vary based on the length of time. If it is 0 seconds, it's displayed in black, and as it takes longer, it transitions to white, and then to increasingly brighter shades of red, maxing out at bright red on a 5 minute run time.
[eli@hostname blog]$ [0s] sleep 5 [eli@hostname blog]$ [5s!] sleep 60 [eli@hostname blog]$ [60s!] sleep 252 [eli@hostname blog]$ [252s!] [eli@hostname blog]$ [0s] sleep 1 [eli@hostname blog]$ [1s] [eli@hostname blog]$ [0s]
So all that code went into a dotscript I called promptautobell:
#!/bin/bash function prompt_autobell_start { prompt_autobell_timer=${prompt_autobell_timer:-$SECONDS} } function prompt_autobell_stop { local retval=$? prompt_autobell_elapsed=$(($SECONDS-$prompt_autobell_timer)) unset prompt_autobell_timer local color local bell if [ $prompt_autobell_elapsed -ge 5 ]; then bell="\001\a\002!" else bell="" fi color="$(tput bold)$(tput setaf $((prompt_autobell_elapsed > 300 ? 196 \ : prompt_autobell_elapsed > 22 ? 16+(1+(prompt_autobell_elapsed-1)/60)*36: \ 233+prompt_autobell_elapsed)))" prompt_autobell_show="$(echo -e "\001${color}\002[\ ${prompt_autobell_elapsed}s$bell]\001$(tput sgr0)\002")" return $retval } trap 'prompt_autobell_start' DEBUG PROMPT_COMMAND="prompt_autobell_stop" PS1="$PS1\${prompt_autobell_show} "
So that's nice, we get to know how long our commands take, and automatically get nudged when a long-running command finally completes.
Return Codes
But that doesn't tell us if the command passed or failed. And in the *NIX tradition, commands are generally silent on success. So what if we make the prompt display an appropriate emoticon based on the exit code? Like, a green smiley on success, and a red frown on failure. And maybe a few other expressions as well.
[eli@hostname blog]$ source ~/bin/promptsmile [eli@hostname blog]$ :) [eli@hostname blog]$ :) false [eli@hostname blog]$ :( sleep 60 ^C [eli@hostname blog]$ :| sleep 60 Terminated [eli@hostname blog]$ x_x sleep 60 Segmentation fault (core dumped) [eli@hostname blog]$ >_< true [eli@hostname blog]$ :)
So into a dotscript called promptsmile goes:
#!/bin/bash # source this function prompt_smile () { local retval=$? if [ $retval -eq 0 ]; then color=46 face=":)" elif [ $retval -eq 1 ]; then color=196 face=":(" elif [ $retval -eq 130 ]; then # INT color=226 face=":|" elif [ $retval -eq 139 ]; then # SEGV color=196 face=">_<" elif [ $retval -eq 143 ]; then # TERM color=196 face="x_x" else color=196 face=";(" fi echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002" return $retval # preserve the value of $? } PS1="$PS1\$(prompt_smile) "
Note that the emoticon logic is readily extensible. Do you frequently deal with a program that has a couple of special exit codes? Make those stand out with a bit of straight-forward customization of the prompt_smile function.
Combined
And of course, I want an easy way to get both of these behaviors at the same time, so I created a dotscript called promptfancy:
source ~/bin/promptautobell source ~/bin/promptsmile
And to make it easy to apply to a shell, I added to ~/.bashrc:
alias fancyprompt="source ~/bin/promptfancy"
And now,
[eli@hostname blog]$ fancyprompt [eli@hostname blog]$ [0s] :) [eli@hostname blog]$ [0s] :) sleep 60 ^C [eli@hostname blog]$ [1s] :| sleep 60 Terminated [eli@hostname blog]$ [12s!] x_x sleep 60 Segmentation fault (core dumped) [eli@hostname blog]$ [12s!] >_< false [eli@hostname blog]$ [0s] :( sleep 6 [eli@hostname blog]$ [6s!] :) [eli@hostname blog]$ [0s] :) [eli@hostname blog]$ [0s] :)
Go then, and liven up your own bash prompts!