Skip to content

BASH

System Wide Configuration

  1. Create directory "/etc/bash.d".
    # mkdir /etc/bash.d
    
  2. Create "/etc/bash.d/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'
    
  3. Create "/etc/bash.d/environment".
    # 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";
    
  4. Create "/etc/bash.d/functions".
    # 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;
    }
    
  5. Replace "/etc/bash.bashrc" with the following.
    # nano /etc/bash.bashrc
    
    # System-wide .bashrc file for interactive bash(1) shells.
    
    # To enable the settings / commands in this file for login shells as well,
    # this file has to be sourced in /etc/profile.
    
    # If not running interactively, don't do anything
    [ -z "$PS1" ] && return
    
    # check the window size after each command and, if necessary,
    # update the values of LINES and COLUMNS.
    shopt -s checkwinsize
    
    # set variable identifying the chroot you work in (used in the prompt below)
    if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
       debian_chroot=$(cat /etc/debian_chroot)
    fi
    
    #left this here as it was commented out previously and we may need it
    # enable bash completion in interactive shells
    #if ! shopt -oq posix; then
    #  if [ -f /usr/share/bash-completion/bash_completion ]; then
    #    . /usr/share/bash-completion/bash_completion
    #  elif [ -f /etc/bash_completion ]; then
    #    . /etc/bash_completion
    #  fi
    #fi
    
    # if the command-not-found package is installed, use it
    if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then
       function command_not_found_handle {
               # check because c-n-f could've been removed in the meantime
                   if [ -x /usr/lib/command-not-found ]; then
              /usr/lib/command-not-found -- "$1"
                      return $?
                   elif [ -x /usr/share/command-not-found/command-not-found ]; then
              /usr/share/command-not-found/command-not-found -- "$1"
                      return $?
           else
             printf "%s: command not found\n" "$1" >&2
              return 127
        fi
       }
    fi
    
    # source system wide 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
    
    # source user specified aliases, environment and profile files
    if [ -f $HOME/.bash_aliases ]; then
       source $HOME/.bash_aliases
    fi
    if [ -f $HOME/.bash_environment ]; then
       source $HOME/.bash_environment
    fi
    if [ -f $HOME/.bash_profile ]; then
       source $HOME/.bash_profile
    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
    

User Specific Configuration

Readline - ArchWiki

Users can create "~/.bash_environment", "~/.bash_aliases" and "~/.bash_profile" files. In most cases you will not need a "~/.bash_profile" file.

  • Create "~/.bash_environment" file.
    $ nano ~/.bash_environment
    
    export HISTTIMEFORMAT='%F %T  # The time format for history entries
    export HISTCONTROL=ignoredups                #ignore duplicate history entries
    export HISTCONTROL=ignorespace               #ignore commands that start with a space
    #NOTE: shorthand for ignoring spaces and duplicates is 'ignoreboth'
    export HISTIGNORE="pwd:ls:ls -l:ls -t:ls -a" #Ignore specific commands like pwd, ls
    
  • Create "~/.bash_aliases" file.
    $ nano ~/.bash_aliases
    
    alias localproj='cd ~/Development/LocalProjects'