Skip to content

Customize BASH Prompt

Customize the BASH (GNU Bourne-Again SHell) shell prompt that is visible in the shell or terminal.

Simple Prompt

Features

Prompt features are broken down in order as they appear.

  • Username of the currently logged in user.
  • Hostname of the connected system.
  • tty (teletype)/pts (psuedo terminal slave) session number on the connected system. TTY, physically at the console. PTS, SSH session.
  • Date and time of the connected system.
  • Current working directory.
  • Total files within the current working directory.
  • Total consumed space of the files within the current working directory.

Prompt Preview

custom-prompt1.png

Installation

  1. Create "/etc/bash.bashrc" file.
    $ sudo nano /etc/bash.bashrc
    
    # set a fancy prompt (non-color, overwrite the one in /etc/profile)
    #PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
    
    clientConnType=$(tty)
    clientConnType=`echo "$clientConnType" | sed -r 's/\/dev\///g'`
    
    PS1="\n\[\e[30;1m\]\[\016\]-\[\017\]($(if [[ ${EUID} == 0 ]]; then echo '\[\033[01;31m\]\u'; else echo '\[\e[34;1m\]\u';fi)\[\e[0;36m\]@\[\e[34;1m\]\h\[\e[30;1m\])-(\[\e[34;1m\]$clientConnType\[\e[30;1m\])-(\[\e[34;1m\]\D{%F} \t\[\e[30;1m\])\[\e[30;1m\]\[\016\]\[\017\]-(\[\[\e[32;1m\]\w\[\e[30;1m\])-(\[\e[00;31m\]\$(/bin/ls -1 | /usr/bin/wc -l | /bin/sed 's: ::g') files, \$(/bin/ls -lah | /bin/grep -m 1 total | /bin/sed 's/total //')b\[\e[30;1m\])\n-> \[\e[0m\]"
    
  2. For changes to take affect restart the session.

Contextual Prompt

Features

Prompt features are broken down in order as they appear.

1st Line: - Date and time on the connected system. - Command history line number. - Session command number. - Connection type, tty (teletype)/pts (psuedo terminal slave) and session number on the connected system. TTY, physically at the console. PTS, SSH session.

2nd Line: - Username of the currently logged in user (blue=regular user, red=root user). - Hostname of the connected system. - Total files within the current working directory. * Current working directory.

3nd Line (contextual these features will appear): - GIT branch name. - GIT branch status (detached, untracked files, commit needed, branch is ahead of upstream and branch is behind of upstream).

4th Line: - The "$" represents a regular user is in use. - The "$" represents a elevated user is in use. - The color green of "$" and "#" represents success of the last command. - The color red of "$" and "#" represents failure of the last command.

Prompt Preview

custom-prompt2.png

Installation

  1. Add the following to the bottom of the file "/etc/bash.bashrc".
    # nano /etc/bash.bashrc
    
    # source our aliases, and environment files
    if [ -f /etc/bash.d/environment ]; then
       source /etc/bash.d/environment;
    fi
    if [ -f /etc/bash.d/aliases ]; then
       source /etc/bash.d/aliases;
    fi
    
    # if running X-based Terminal in a local X session
    if [ !-x ${DISPLAY} ]; then
      case ${TERM} in
        xterm*|rxvt*|Eterm|aterm|kterm|gnome*)
          PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND; }'printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
          ;;
         screen)
           PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND; }'printf "\033_%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"'
           ;;
       esac
    fi
    
    # source bash completion if user can read /usr/share/bash-completion/bash_completion
    [ -r /usr/share/bash-completion/bash_completion   ] && . /usr/share/bash-completion/bash_completion
    
  2. Create a new directory "/etc/bash.d".
    $ sudo mkdir /etc/bash.d
    
  3. Add global system aliases.
    # nano /etc/bash.d/aliases
    
    # if /usr/bin/dircolors exists & we can execute it
    if [ -x /usr/bin/dircolors ]; then
       test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
       alias ls='ls --color=auto'
       alias tree='tree -C'
       alias dir='dir --color=auto'
       alias grep='grep --color=auto'
       alias dmesg='dmesg -T --color' #-T makes human readable timestamps
    fi
    
    alias ll='ls -al'
    alias la='ls -A'
    alias l='ls -CF'
    
  4. Create the environment file.
    # nano /etc/bash.d/environment
    
    #load the functions file, return if is not present
    if [ -f "/etc/bash.d/functions" ]; then
       source /etc/bash.d/functions;
    else
       echo "Functions file missing in /etc/bash.d";
       return;
    fi
    
    export PROMPT_COMMAND=prompt_generator;
    export EDITOR="/usr/bin/nano";
    
  5. Create the functions file.
    # nano /etc/bash.d/functions
    
    #copied verbatim from OSX El Capitan /etc/bash_bashrc_Apple_Terminal
    update_terminal_cwd () {
       local url_path='';
       {
          local i ch hexch LC_CTYPE=C LC_ALL=;
           for ((i = 0; i < ${#PWD}; ++i))
          do
               ch="${PWD:i:1}";
               if [[ "$ch" =~ [/._~A-Za-z0-9-] ]]; then
                   url_path+="$ch";
               else
                   printf -v hexch "%02X" "'$ch";
                   url_path+="%${hexch: -2:2}";
               fi;
           done
       };
       printf '\e]7;%s\a' "file://$HOSTNAME$url_path"
    }
    
    function prompt_generator() {
    local EXIT=$?; #get last command exit status before doing anything else
    
    #this is done to force PS1 to a newline if the cursor ended up somewhere other than the last margin
    PS1='$(printf "%$((COLUMNS-1))s\r")';
    
    # Reset
    local Color_Off='\[\e[0m\]';       # Text Reset
    
    # ASCII Foreground Colors            Bold                         High Intensity            Bold High Intensity
    local Red='\[\e[0;31m\]';       local BRed='\[\e[1;31m\]';       local IRed='\[\e[0;91m\]';      local BIRed='\[\e[1;91m\]';
    local Green='\[\e[0;32m\]';     local BGreen='\[\e[1;32m\]';     local IGreen='\[\e[0;92m\]';    local BIGreen='\[\e[1;92m\]';
    local Yellow='\[\e[0;33m\]';    local BYellow='\[\e[1;33m\]';    local IYellow='\[\e[0;93m\]';   local BIYellow='\[\e[1;93m\]';
    local Blue='\[\e[0;34m\]';      local BBlue='\[\e[1;34m\]';      local IBlue='\[\e[0;94m\]';     local BIBlue='\[\e[1;94m\]';
    local Purple='\[\e[0;35m\]';    local BPurple='\[\e[1;35m\]';    local IPurple='\[\e[0;95m\]';   local BIPurple='\[\e[1;95m\]';
    local Cyan='\[\e[0;36m\]';      local BCyan='\[\e[1;36m\]';      local ICyan='\[\e[0;96m\]';     local BICyan='\[\e[1;96m\]';
    local White='\[\e[0;37m\]';     local BWhite='\[\e[1;37m\]';     local IWhite='\[\e[0;97m\]';    local BIWhite='\[\e[1;97m\]';
    local Gray='\[\e[0;90m\]';
    local LightGray='\[\e[0;30m\]';
    
    # ASCII High Intensity Background Colors
    local On_IBlack='\[\e[0;100m\]';   # Black
    local On_IRed='\[\e[0;101m\]';     # Red
    local On_IGreen='\[\e[0;102m\]';   # Green
    local On_IYellow='\[\e[0;103m\]';  # Yellow
    local On_IBlue='\[\e[0;104m\]';    # Blue
    local On_IPurple='\[\e[0;105m\]';  # Purple
    local On_ICyan='\[\e[0;106m\]';    # Cyan
    local On_IWhite='\[\e[0;107m\]';   # White
    
    #256 Foreground Colors
    local Orange='\[\e[38;5;209m\]';
    
    # Glyphs http://www.utf8-chartable.de/unicode-utf8-table.pl?start=9472&number=1024
    local Checkmark="${BIGreen}$( echo -e "\xE2\x9C\x93" )${Color_Off}";
    local Xmark="${BIRed}$( echo -e "\xE2\x9C\x95" )${Color_Off}";
    local Lines_Color=$White;
    
    local Light_Down_Right="${Lines_Color}$(echo -e "\xE2\x94\x8C")${Color_Off}";
    local Light_Vert_Right="${Lines_Color}$(echo -e "\xE2\x94\x9C")${Color_Off}";
    local Light_Up_Right="${Lines_Color}$(echo -e "\xE2\x94\x94")${Color_Off}";
    local Left_Square="${Lines_Color}$( echo -e "\xE2\x9F\xA6" )";
    local Right_Square="$( echo -e "\xE2\x9F\xA7" )${Color_Off}";
    local Line="${Lines_Color}$(echo -e "\xE2\x94\x80" )${Color_Off}";
    
    local Start_Parenthesis="${Lines_Color}(${Color_Off}";
    local End_Parenthesis="${Lines_Color})${Color_Off}";
    
    local Exit_Status_Color=$BIGreen
    if [ $EXIT != 0 ]; then
        Exit_Status_Color=$BIRed;
    fi
    
    local PROMPT="${Exit_Status_Color}\$ ${Color_Off}";
    local UsernameColor="${BIBlue}";
    
    #turn username red if root
    if [ $EUID == 0 ]; then
        UsernameColor="${BIRed}";
        PROMPT="${Exit_Status_Color}# ${NarrowSpace}${Color_Off}";
    fi
    
    #command separator
    PS1+="${Gray}";
    let Fillsize=${COLUMNS}-60;
    while [ $Fillsize -gt 0 ]
    do
        PS1+='-';
        let Fillsize-=1;
    done
    #timestamp
    PS1+="${Left_Square}\D{%Y-%m-%d} \t${Right_Square}";
    
    #command history line number
    PS1+="${Line}${Left_Square}History: \!${Right_Square}";
    
    #session command number
    PS1+="${Line}${Left_Square}Session: \#${Right_Square}"
    
    #TTY
    PS1+="${Line}${Left_Square}$(tty | awk 'BEGIN { FS = "/" } ; {print $3"/"$4}')${Right_Square}";
    
    #should be one char left to fill
    PS1+="${Gray}-${Color_Off}";
    
    #username@FQD_hostname
    PS1+="\n${Light_Down_Right}${UsernameColor}\u${Color_Off}";
    PS1+="${Lines_Color}@${Color_Off}";
    PS1+="${BIGreen}\H${Color_Off}";
    
    #pwd
    PS1+="${Line}${Start_Parenthesis}$( ls -a | wc -l | awk '{print $1 " files"}' )${End_Parenthesis}";
    PS1+="${Line}${Start_Parenthesis}\w${End_Parenthesis}";
    
    #if we are in a directory that contains a .git folder, do magic!
    local Git_Branch;
    if Git_Branch=$(git rev-parse --abbrev-ref HEAD 2> /dev/null); then
        PS1+="\n${Light_Vert_Right}${Start_Parenthesis}GIT Branch: ";
        if [ $Git_Branch == 'HEAD' ]; then
                PS1+="detached*";
        else
            PS1+="$Git_Branch";
        fi
        PS1+="${End_Parenthesis}";
    
        local Short_Status_Array=( $(git status --porcelain 2> /dev/null) );
        local Commit_Needed=false;
        local Long_Status_Array=$(git status 2> /dev/null);
    
        if [[ "${Short_Status_Array[@]}" =~ "??" ]]; then
            PS1+="${Line}${Start_Parenthesis}${Red}Untracked files present!${Color_Off}${End_Parenthesis}";
        fi
    
        if [[ "${Short_Status_Array[@]}" =~ [MADRCU] ]]; then
            PS1+="${Line}${Start_Parenthesis}${Orange}Commit Needed!${Color_Off}${End_Parenthesis}";
        fi
    
        if [ $Commit_Needed == false ]; then
            if [[ ${Long_Status_Array[@]} =~ 'Your branch is ahead of' ]]; then
                PS1+="${Line}${Start_Parenthesis}${Cyan}Push needed.${Color_Off}${End_Parenthesis}";
            elif [[ ${Long_Status_Array[@]} =~ 'Your branch is behind' ]]; then
                PS1+="${Line}${Start_Parenthesis}${BIRed}Behind upstream! 'git pull --rebase' required!${Color_Off}${End_Parenthesis}";
            fi
        fi
    fi
    
       #prompts
       PS1+="\n${PROMPT}";
       update_terminal_cwd;
    }
    
  6. For changes to take affect restart the session.

Last update: August 9, 2020