I currently maintain a repository with my current dotfiles which you can clone here:

git clone https://github.com/richinfante/dotfiles.git

~/.bash_profile

First, I start with some configuration options. Depending on the system I may change these in the config file (~/.bash_config)

# Customizable Options
GIT_BRANCH_CHAR="↳"
PROMPT_GIT="true"
PROMPT_DATE="false"

# If we're in a tty,
if [ -t 1 ] ; then
  export TERM=xterm-256color
  COLORS_ENABLED=true
  # Bash tab completion
  bind 'TAB:menu-complete'
fi

# Run Bash config
if [ -f ~/.bash_config ]; then
  source ~/.bash_config
fi

Next, I set up color support. This includes variables for light/dark variants, as well as control sequences for resetting and blinking text.

# Colors
if [ "$COLORS_ENABLED" != "false" ]; then
  
  export RED="\033[31m"
  export LIGHT_RED="\033[91m"

  # ... (removed for brevity)

  export RESET="\033[0m"
  export BOLD="\033[1m"
  export DIM="\033[2m"
  export UNDERLINE="\033[4m"
  export BLINK="\033[5m"
  export INVERTED="\033[7m"
  export HIDDEN="\033[8m"
fi 

Since I’ve been experimenting with debian chroot recently, I’ve copied this line from the default debian ~/.bashrc file:

# Debian CHROOT Support
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
  debian_chroot=$(cat /etc/debian_chroot)
fi

The prompt string! This is a bit complicated. The date section, git section, shell type are all scripts that are enclosed in an escaped $() block. They are set into the $PS1 as strings and aren’t evaluated when the bash_profile script runs. The debian chroot block, as well as the host section, are immediately evaluated here.

# Bash Prompt String
export PS1="\[$RESET\]\$(\
  $(
    # DATE SECTION
    # This is run on every new line.
  )\
  if [[ \"\$PROMPT_DATE\" == \"true\" ]]; then\
   echo \"\[$DIM$GRAY\]\D\{\%Y-%m-%d %H:%M:%S} \";\
  else\
    echo \"\";
  fi\
)\
$(
  # HOST SECTION
  # (hidden if not using ssh or remote)
)\
\[$RESET\]\[$WHITE\]\[$BOLD\]\
${debian_chroot:+($debian_chroot) }\u$(\
 if [ -n "$SSH_CLIENT" ] || \
    [ -n "$SSH_TTY" ] || \
    [ -f /.dockerenv ]; then \
  echo "@\h";\
 fi
): \
$(
  # USER NAME
)\
\[\]\w \
$(
  # GIT COMPONENT
  # Attempt to get git branch
  # Errors piped to stdout so if no branch, no display.
)\
\[$LIGHT_BLUE\]\$(\
  if [[ \"\$PROMPT_GIT\" == "true" ]]; then\
    if git diff-index --quiet HEAD -- 2> /dev/null; then\
      git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/('"$GIT_BRANCH_CHAR"' \1) /';\
    else \
      git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/('"$GIT_BRANCH_CHAR"' \1 \*) /';\
    fi\
  fi\
)\
$(
  # SHELL TYPE INDICATOR
  # "$" or "#" depending on user/superuser
)\
\[$GREEN\]\$(\
  if [[ `whoami` == "root" ]]; then \
    echo '#'; \
    else echo '$';\
  fi\
)\[$RESET\] "

The $PS2 indicators are used for continuing entry on a new line. $PS4 is used when using set -x inside of a shell script, and is echoed before each command.

export PS2="\[$DIM$GRAY\]> \[$RESET\]"
export PS4="\[$DIM$GRAY\]+ \[$RESET\]"

Next, we enable some color support flags here:

# Enable some colors
if [ "$COLORS_ENABLED" != "false" ]; then
  export CLICOLOR=1
  export LSCOLORS=hxfxcxdxbxegedabagacad
  export GREP_OPTIONS='--color=auto'
  # alias ls='ls --color=auto'
fi

$PATH construction. There are two flavors here. the export_path function checks if a path exists BEFORE generating the path. others using the traditional method (for example, relative paths) are always added to the search $PATH.

# Export paths only if they exist.
function export_path {
  if [ -d "$1" ]; then
    export PATH="$PATH:$1"
  fi
}

# Path variables
export PATH="/usr/local/bin"
export_path "/bin"
export_path "/sbin"
export_path "/usr/bin"
export_path "/usr/sbin"
export_path "/Applications/Postgres.app/Contents/Versions/latest/bin"
export_path "$HOME/.local/bin"
export_path "$HOME/.npm-global/bin"
export_path "$HOME/.fastlane/bin"
export_path "$HOME/.cargo/bin"
export_path "$HOME/bin"
export_path "/Applications/Sublime Text.app/Contents/SharedSupport/bin/"

# Since export_path is conditional, we must add directory-dependent paths here:
export PATH="$PATH:./node_modules/.bin"

Since some systems don’t adhere to these paths or requrie installation specific ones, I add them in this separate file, called ~/.bash_path. This allows me to keep this file portable while installation specific things can be done here:

# Source custom paths.
if [ -f ~/.bash_path ]; then
  source ~/.bash_path
fi

Git completion support:

# Add git completion
if [ -f ~/scripts/git-completion.bash ]; then
  source ~/scripts/git-completion.bash
fi

Custom shortcuts for various tasks, aliases to make life easier:

# Shortcuts
alias finder='open .'
alias l='ls -a'
alias ll='ls -l'
alias la='ls -la'
alias root='sudo su'
alias serve='python -m SimpleHTTPServer 8888'
alias prettyjson='python -m json.tool'
alias c='code'
alias s='subl'
alias t='tmux new-session -A -s main'
alias pdb='python -m pdb'
alias lowercase='tr "[:upper:]" "[:lower:]"'
alias uppercase='tr "[:lower:]" "[:upper:]"'

Support functions for gpg, etc. of note is the dvm shortcut that I use frequently alongside docker to allow for quick virtualization of linux systems on my mac:

# Shortcut to make GPG forget cached passwords.
function gpg-forget { echo RELOADAGENT | gpg-connect-agent; }

# Open in projects folder
function p { cd ~/Projects/$@; }

# Create and open a directory
function cf { mkdir $@; cd $@; }

# youtube-mp3
function youtube-mp3 { youtube-dl --extract-audio --audio-format mp3 -o "%(title)s.%(ext)s" $@; }

# Hash functions
function sha1 { openssl sha1 $@; }
function sha256 { shasum -a 256 $@; }

# Start and attach a docker instance.
function dvm { docker start $@ 1>/dev/null; docker attach $@; }

Final configuration:

# Bash History
HISTCONTROL=ignoreboth

# GPG Support
GPG_TTY=$(tty)
export GPG_TTY 

That’s it!