I’ve been spending a lot of time thinking about how I can improve my bash productivity and understand when / why things have gone wrong sooner.

Luckily, I stumbled upon this golden blog post by Jake McCrary.

Put the last command’s run time in your Bash prompt via @climagic #linux #unix #programming https://t.co/vdi521B4a2

— nixCraft # (@nixcraft) September 15, 2016

I decided to adopt some of his prompt suggestions on tracking the last command and put my own spin on the additions.

Automatically Time Your Last Command

Often, I find myself updating a sequence of commands iteratively. Eventually, I get curious about the perf gains of this process, but of course, I’ve forgotten to time the sequences I’ve been executing. That’s why I’m so glad I caught this tweet, which highlights a way of constantly displaying time for your last command, and tracking it in your prompt.

This gives me a quick and easy way to check perf differences as I incrementally chain things together and make improvements to my bash commands.

I used the code directly from Jake’s blog post to get this going.

Reducing Debug Time with Conditional Exit Codes

Sometimes, when I run a bash command, I don’t immediately realize that it has failed, or if it has, it takes me quite some time to figure out why, especially if I’m using redirection to send stdout and stderr to capture a bunch of stuff in a log file, something I often do while working in bash.

Let’s use grep as an example.

grep "fancy" somefile.txt &> logs.txt

I expect it to print lines that contain “fancy” to logs.txt, along with any issues.

Okay, but what if I accidentally typed greb instead of grep?

The error message, -bash: greb: command not found wouldn’t be immediately apparent, since the &> redirection sends both my output and errors to logs.txt.

But, this conditional prompt tells me immediately that something’s gone wrong.

Display of red erroneous exit code 127 in bash prompt

An exit code of 127 means “command not found”, so even if I don’t see the error output right away, I can discover rather quickly that my last command failed, likely due to a command typo.

I like a minimal prompt, so rather than always displaying the last exit code, $?, all the time, I only have it display in red when something goes wrong. So only when the exit code is not 0.

Here’s the code for a conditional error exit code displayed in red:

PROMPT_COLOR="$(tput setaf 4)"
ALERT_COLOR="$(tput setaf 1)"

# Display unsuccessful exit codes
function exit_status {
    if [[ $last_status != 0 ]]; then
        echo "$ALERT_COLOR[Exit: $last_status]$PROMPT_COLOR"

Then add $(exit_status) to your PS1 variable to get it to appear in your prompt.

You can see both of these prompt additions in their entirety on my GitHub.

Lessons Learned from Mistakes

A mistake I made while making these two additions was accidentally wrapping everything in PS1 in double quotes. I mean, that’s how I normally would expand variables and run functions in a bash script, right?

Tripped me up for three hours this morning. TIL that $PS1 in dot files has different single-quote behavior: https://t.co/SbXTYnE3L5 #bash

— ǝuıɐɹo˥ (@lorainekv) September 19, 2016

Whoops! This was a good reminder for me to test early and often.