BASH prompt

I know it’s cliché, but I thought I’d post my BASH prompt just in case anyone finds it useful. Features include:

  • username, host, and directory
  • number of background jobs
  • exit status of last command
  • wall-clock time of last command
  • current date/time
  • horizontal rule to separate outputs
  • resizable

bash-prompt-example

The duration of the last command is based on the actual duration, not just time between prompt displays, so it doesn’t include time spent sitting idle at the prompt.  By resizable, I mean that the width of the horizontal rule is based on the width of the terminal, so resizing the window will affect the size of new horizontal rules.

The following is the code I put in my .bashrc, ignoring checks on whether features like color are enabled.  It assumes you have bc installed, but it could theoretically be re-written to use BASH arithmetic.  I used a trick posted on superuser to run commands before the user’s command.

_ps1_preexec () {
    [ -n "$COMP_LINE" ] && return  # do nothing if completing
    [ "$BASH_COMMAND" = "$PROMPT_COMMAND" ] && return # don't cause a preexec for $PROMPT_COMMAND

    _ps1_start_ts=${_ps1_start_ts:-$(date '+scale=3; %s+%N/1000000000' | bc)}
}

trap '_ps1_preexec' DEBUG

function _ps1_display_prompt2 {
    if [ "$_ps1_start_ts" != "" ]; then
        _ps1_duration=$(date "+scale=3; %s+%N/1000000000-$_ps1_start_ts" | bc)
    else
        unset _ps1_duration
    fi
    unset _ps1_start_ts
}

PROMPT_COMMAND=_ps1_display_prompt2

function _ps1_display_prompt {
    local boxch_h="\u2500"
    local bold="\033[01m"
    local reset="\033[00m"
    local black="\033[30m"
    local red="\033[31m"
    local green="\033[32m"
    local blue="\033[34m"
    local s1="${USER}@$(hostname)"
    local s2="$1"
    local s3="$(date)"
    local status=""
    local exit_status="$2"
    local jobcount="$3"
    if [ "$exit_status" != "0" ]; then
        status="$status ${bold}${red}exit:$exit_status$reset"
    fi
    if [ "$jobcount" != "0" ]; then
        status="$status jobs:$jobcount"
    fi

    if [ "$_ps1_duration" != "" ]; then
        status="$status duration:${_ps1_duration}s"
    fi
    if [ "$status" != "" ]; then
        status="${status:1}" # strip leading space
    fi
    local status_stripped=$(echo "$status" | sed -r 's/\\033\[[^m]+m//g')

    local hrlen=$(($(tput cols) - ${#s1} - ${#s2} - 3 - ${#s3} - 2))
    local status_box=""
    if [ "$status" != "" ]; then
        hrlen=$(($hrlen - ${#status_stripped} - 3))
        status_box="${boxch_h}[${status}]"
    fi
    local hr=$(for alias_hr_i in $(seq 1 $hrlen); do echo -en $boxch_h; done)
    echo -en "[${bold}${green}${s1}${reset}:${bold}${blue}${s2}${reset}]${status_box}${hr}[${bold}${black}${s3}${reset}]\n\$ "
}

PS1='$(_ps1_display_prompt "\w" $? \j)'

Post a Comment

Your email is never shared. Required fields are marked *

*
*