Skip to content

Instantly share code, notes, and snippets.

@rbf
Last active June 28, 2021 18:10
Show Gist options
  • Save rbf/1844923 to your computer and use it in GitHub Desktop.
Save rbf/1844923 to your computer and use it in GitHub Desktop.
Enhanced Terminal Prompt for Mac OS X (keywords: bash, shell)
# Repeat a command N times
# From: http://www.stefanoforenza.com/how-to-repeat-a-shell-command-n-times/
repeat() {
n=$1
shift
while [ $(( n -= 1 )) -ge 0 ]
do
"$@"
done
}
# Goes to N directories upwards.
# ${1-1} means the first argument or the default value "1" if it is not set.
# ${parameter-default} as from: http://tldp.org/LDP/abs/html/parameter-substitution.html
up() {
repeat ${1-1} cd ..
}
# System-wide .profile for sh(1)
# To be placed in /etc/profile or ~/.bash_profile
if [ -x /usr/libexec/path_helper ]; then
eval `/usr/libexec/path_helper -s`
fi
# include .bashrc if it exists
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
# include .bash_aliases if it exists
if [ -f ~/.bash_aliases ]; then
source ~/.bash_aliases
fi
alias reload='source ~/.bash_profile'
alias reload_prompt='source ~/.bashrc'
alias dev="cd ~/Dropbox/dev"
alias la='ls -la'
alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"
alias showall='defaults write com.apple.Finder AppleShowAllFiles true'
alias showallnot='defaults write com.apple.Finder AppleShowAllFiles false'
# System-wide .bashrc file for interactive bash(1) shells.
###############################################################################
# Custom commands and aliases
###############################################################################
# Repeat a command N times
# From: http://www.stefanoforenza.com/how-to-repeat-a-shell-command-n-times/
repeat() {
n=$1
shift
while [ $(( n -= 1 )) -ge 0 ]
do
"$@"
done
}
# Create N number of files with given ext in the current dir
# Used without params, it creates 1 file of the form tmp-XXXX.txt
tmpfiles() {
n="${1:-1}"
extention="${2:-txt}"
extention="${extention#.}"
while [ $(( n -= 1 )) -ge 0 ]
do
f=$(mktemp "tmp-XXXX")
mv "${f}" "${f}.${extention}"
done
}
# Goes to N directories upwards.
# ${1-1} means the first argument or the default value "1" if it is not set.
# ${parameter-default} as from: http://tldp.org/LDP/abs/html/parameter-substitution.html
up() {
repeat ${1-1} cd ..
}
# Goes to the previous directory
back() {
cd "${OLDPWD}"
}
# Goes to the home directory
home() {
cd ~
}
# Change directory creating it if it doesn't exists.
cdf() {
if [ ! -d $1 ]; then
mkdir -p $1;
fi
cd $1;
}
datestamp() {
echo $(date +"%Y%m%d")
}
timestamp() {
echo $(date +"%Y%m%d%H%M%S")
}
# cdf into a folder with current date
today() {
if [[ "$(basename $(pwd))" =~ 20[1-9][0-9][0-1][0-9][0-3][0-9] ]]; then
echo "Already in a datestamped folder: $(pwd)"
echo "Nothing to do."
else
cdf "$(datestamp)"
fi
}
# Generate uuid using Python
uuid() {
repeat ${1-1} python -c "import uuid; print uuid.uuid4();"
}
# Duplicate a file adding the extention .bak_[timestamp]
backup() {
if [ -z "${1}" ]
then
echo "Missing file to backup. Nothing to do."
return 1
fi
BACKUP_FILENAME="${1}.bak_$(date +"%Y%m%d%H%M%S")";
cp "${1}" "${BACKUP_FILENAME}" && echo "Backup created: ${BACKUP_FILENAME}";
}
create_subl_project_file() {
filename="$(basename $(pwd)).sublime-project"
[ -f "${filename}" ] && backup "${filename}"
cat << EOF > "${filename}"
{
"folders":
[
{
"path": ".",
"folder_exclude_patterns": ["tmp", "bin", "log"],
}
]
}
EOF
echo "${filename}"
}
stt() {
filename="$(ls -1 *.sublime-project 2>/dev/null | head -1)"
if [ -z "${filename}" ];then
echo "Creating a default '.sublime-project' file for this folder..."
filename="$(create_subl_project_file)"
fi
echo "Opening project ${filename} with SublimeText 3..."
subl --project "${filename}"
}
# List files (containing $2 in the name) containing a string ($1) begining from the current dir
# "${@:3}" Stands for all parameters from the third (included) on. (From: http://wiki.bash-hackers.org/scripting/posparams#mass_usage)
hgrep() {
if [ $# -gt 0 ]; then
egrep "$1" -i -n -r . --colour --include "*$2*" "${@:3}"
fi
}
# lsnc List Network Connections
lsnc(){
lsof -i -n -c 16| awk '{print $1 "\t\t" $9 " " $10}' | uniq | grep -v COMMAND | egrep -v "\->127.0.0.1:.*"
}
# Primarily used for the prompt function.
truncate_string() {
local string="${1}"
local maxlen=${2:-25}
local trunc_symbol=${3:-"…"}
if [ "${#string}" -gt "${maxlen}" ]; then
string="${string:0:$maxlen}${trunc_symbol}"
fi
echo "${string}"
}
alias la='ls -laGFTB'
# To make it equivalent to CentOS machines and others deployed with SlipStream
alias ll='ls -lG'
alias tree="find . -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'"
alias showall='defaults write com.apple.Finder AppleShowAllFiles true'
alias showallnot='defaults write com.apple.Finder AppleShowAllFiles false'
# Include user custom aliases if defined
if [ -f ~/.bash_aliases ]; then
source ~/.bash_aliases
fi
alias reload_aliases='source ~/.bash_aliases'
alias reload_bashrc='source /etc/bashrc'
###############################################################################
# Enhanced Terminal Prompt
# Mac OS X 10.6 Version (Snow Leopard)
# Original from: http://phil.cryer.us/code/dotfiles/bashrc
###############################################################################
# Example:
# 14:42:52 username@hostname ~/somedirectory$
# In directories with a git repository, it will display the current branch in:
# - green: for a clean branch (HEAD and index clean)
# - orange: if the HEAD is clean but there are files to commit in the index
# - red: if there are modified files in the HEAD
# Original from: http://vvv.tobiassjosten.net/bash/dynamic-prompt-with-git-and-ansi-colors
# Example:
# 14:42:52 username@hostname ~/somedirectory [master]$
# To be placed in /etc/bashrc or ~/.bashrc
##################################################
# Fancy PWD display function
##################################################
# The home directory (HOME) is replaced with a ~
# The last pwdmaxlen characters of the PWD are displayed
# Leading partial directory names are striped off
# /home/me/stuff -> ~/stuff if USER=me
# /usr/share/big_dir_name -> ../share/big_dir_name if pwdmaxlen=20
##################################################
bash_prompt_command() {
local OLD_PWD="${NEW_PWD}"
# How many characters of the $PWD should be kept
local pwdmaxlen=24
# Indicate that there has been dir truncation
local trunc_symbol=".."
local dir=${PWD##*/}
pwdmaxlen=$(( ( pwdmaxlen < ${#dir} ) ? ${#dir} : pwdmaxlen ))
NEW_PWD=${PWD/$HOME/\~}
local pwdoffset=$(( ${#NEW_PWD} - pwdmaxlen ))
if [ ${pwdoffset} -gt "0" ]
then
NEW_PWD=${NEW_PWD:$pwdoffset:$pwdmaxlen}
NEW_PWD=${trunc_symbol}/${NEW_PWD#*/}
fi
# Check if we changed dir since last time
local IS_NEW_PWD=false
if [ "${NEW_PWD}" != "${OLD_PWD}" ]; then
local IS_NEW_PWD=true
fi
# Setup variable for current git branch, if available
if ! git rev-parse --git-dir > /dev/null 2>&1; then
GIT_CURRENT_BRANCH=""
GIT_CURRENT_BRANCH_STATE_COLOR=""
GIT_CURRENT_BRANCH_UNTRACKED_FILES=""
else
if ! git diff --quiet 2>/dev/null >&2; then
GIT_CURRENT_BRANCH_STATE_COLOR='\[\033[0;31m\]' #git dirty HEAD
else
if ! git diff --cached --quiet 2>/dev/null >&2; then
GIT_CURRENT_BRANCH_STATE_COLOR='\[\033[0;33m\]' #git dirty index
else
GIT_CURRENT_BRANCH_STATE_COLOR='\[\033[0;32m\]' #git clean branch
fi
fi
if git ls-files --others --exclude-standard --error-unmatch "./$(git rev-parse --show-cdup 2>/dev/null)" 2>/dev/null >&2; then
GIT_CURRENT_BRANCH_UNTRACKED_FILES='+??' #git untracked files
else
GIT_CURRENT_BRANCH_UNTRACKED_FILES='' #git no untracked files
fi
GIT_CURRENT_BRANCH="$(git branch 2>/dev/null| sed -n '/^\*/s/^\* //p')${GIT_CURRENT_BRANCH_UNTRACKED_FILES}"
GIT_CURRENT_BRANCH=" [$(truncate_string "${GIT_CURRENT_BRANCH}" 15)]"
fi
bash_prompt # call again this function to update PS1 to use corresponding GIT_CURRENT_BRANCH_STATE_COLOR
if $IS_NEW_PWD && [ -n "${GIT_CURRENT_BRANCH}" ]; then
( [ -n "$(git remote)" ] && ping -t 1 -c 1 github.com 1>/dev/null && git fetch & ) # Silent and async
# [ -n "$(git remote)" ] && ping -t 1 -c 1 github.com 1>/dev/null && git fetch # Silent and sync
git status -sb
fi
}
bash_prompt() {
local NONE='\[\033[0m\]' # unsets color to term's fg color
# NB: Unused Colors disabled
# regular colors
# local K='\[\033[0;30m\]' # black
local R='\[\033[0;31m\]' # red
# local G='\[\033[0;32m\]' # green
# local Y='\[\033[0;33m\]' # yellow
local B='\[\033[0;34m\]' # blue
# local M='\[\033[0;35m\]' # magenta
# local C='\[\033[0;36m\]' # cyan
# local W='\[\033[0;37m\]' # white
# empahsized (bolded) colors
# local EMK='\[\033[1;30m\]'
# local EMR='\[\033[1;31m\]'
# local EMG='\[\033[1;32m\]'
# local EMY='\[\033[1;33m\]'
# local EMB='\[\033[1;34m\]'
# local EMM='\[\033[1;35m\]'
# local EMC='\[\033[1;36m\]'
# local EMW='\[\033[1;37m\]'
# background colors
# local BGK='\[\033[40m\]'
# local BGR='\[\033[41m\]'
# local BGG='\[\033[42m\]'
# local BGY='\[\033[43m\]'
# local BGB='\[\033[44m\]'
# local BGM='\[\033[45m\]'
# local BGC='\[\033[46m\]'
# local BGW='\[\033[47m\]'
local UC=$C # user's color
[ $UID -eq "0" ] && UC=$R # root's color
#PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
#PS1="${EMK}[${UC}\u${EMR}@${UC}\h ${EMB}\${NEW_PWD}${EMK}]${UC}\\$ ${NONE}"
if [ -z ${TMUX+x} ]; then
# TMUX is not set, so we are not in a TMUX session
# We include the username and hostname into the prompt
PS1="${NONE}\t ${R}\u@\h ${B}\${NEW_PWD}${NONE}${G}${GIT_CURRENT_BRANCH_STATE_COLOR}\${GIT_CURRENT_BRANCH}${NONE}\$ ${NONE}"
# PS1="${NONE}[\t${NONE}] ${NONE}[${R}\u${R}@${R}\h ${B}\${NEW_PWD}${NONE}]${G}${GIT_CURRENT_BRANCH_STATE_COLOR}\${GIT_CURRENT_BRANCH}${NONE}\\$ ${NONE}"
else
# TMUX is set, so we are in a TMUX session
# We don't need to include the username and hostname into the prompt since it's in TMUX's status bar.
PS1="${NONE}\t ${B}\${NEW_PWD}${NONE}${G}${GIT_CURRENT_BRANCH_STATE_COLOR}\${GIT_CURRENT_BRANCH}${NONE}\$ ${NONE}"
fi
SUDO_PS1="${NONE}[\t${NONE}] ${NONE}[${R}\u${R}@${R}\h ${B}\${NEW_PWD}${NONE}]${G}\${GIT_CURRENT_BRANCH}${NONE}\\$ ${NONE}"
}
PROMPT_COMMAND=bash_prompt_command
bash_prompt
#unset bash_prompt # Don't unset this function if updating the PS1 variable every time
# autocompletes
# NOTE: To install the git autocomplete script execute:
# sudo curl -sSL https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash -o /etc/bash_completion.d/git-completion.bash --create-dirs
if [ ! -f /etc/bash_completion ]; then
# In case the /etc/bash_completion file exists, is surely already called by the former bashrc.
for f in /etc/bash_completion.d/*; do
[ -f $f ] && source $f
done
# brew is probably installing completion scripts here
if [ -d /usr/local/etc/bash_completion.d/ ]; then
for f in /usr/local/etc/bash_completion.d/*; do
[ -f $f ] && source $f
done
fi
fi
#ORIGINAL BASHRC PS1 DEFINITION:
#if [ -z "$PS1" ]; then
# return
#fi
#
#PS1='\h:\W \u\$ '
# Make bash check its window size after a process completes
shopt -s checkwinsize
# SOURCE: https://discourse.brew.sh/t/failed-to-set-locale-category-lc-numeric-to-en-ru/5092/12
export LC_ALL=en_US.UTF-8
# Change behavior of fzf dialogue
# SOURCE: https://medium.com/free-code-camp/fzf-a-command-line-fuzzy-finder-missing-demo-a7de312403ff
# SOURCE: https://gist.github.com/samoshkin/efc6672b13b4244f000cfc4b0c4d6125
export FZF_DEFAULT_OPTS="--no-mouse --height 50% --select-1 --reverse --multi --inline-info --preview='if [[ -d {} ]]; then ls -lahGFTB {}; elif [[ \$(file --mime {}) =~ binary ]]; then echo {} is a binary file; else (BAT_LINE=\$(echo {} | grep \":\\d\\d*\\b\" | sed \"s/[^:]*:\([0-9][0-9]*\).*/\\1/g\"); bat \$(echo {} | sed \"s/:.*//g\") \$( [ -n \"\${BAT_LINE}\" ] && echo \"--highlight-line \${BAT_LINE} --line-range \$(( \${BAT_LINE} - 10 < 1 ? 1 : \${BAT_LINE} - 10 )):\") --style=numbers --color=always || cat {}) 3> /dev/null | head -300; fi;' --preview-window='right:wrap' --bind='space:execute(bat --style=numbers {} || less -f {}),ctrl-p:toggle-preview,ctrl-d:half-page-down,ctrl-u:half-page-up,ctrl-a:select-all+accept,ctrl-y:execute-silent(echo {+} | pbcopy),ctrl-o:execute(vim {+})+accept,esc:cancel'"
[ -f ~/.fzf.bash ] && source ~/.fzf.bash
# SOURCE: https://github.com/junegunn/fzf#settings
# Use fd (https://github.com/sharkdp/fd) instead of the default find
# command for listing path candidates.
# - The first argument to the function ($1) is the base path to start traversal
# - See the source code (completion.{bash,zsh}) for the details.
_fzf_compgen_path() {
fd --hidden --follow --exclude ".git" . "$1"
}
# Use fd to generate the list for directory completion
_fzf_compgen_dir() {
fd --type d --follow --exclude ".git" . "$1"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment