├── .gitignore ├── README.md ├── bashrc.local.site ├── contrib ├── install-local └── install-system-wide └── bashrc /.gitignore: -------------------------------------------------------------------------------- 1 | ## MAC OS 2 | .DS_Store 3 | 4 | ## TEXTMATE 5 | *.tmproj 6 | tmtags 7 | 8 | ## EMACS 9 | *~ 10 | \#* 11 | .\#* 12 | 13 | ## VIM 14 | *.swp 15 | 16 | ## PROJECT::SPECIFIC 17 | bashrc.local 18 | tip.date 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Installation 2 | 3 | ### System-Wide Deployment 4 | 5 | ```sh 6 | curl -L https://raw.githubusercontent.com/fnichol/bashrc/master/contrib/install-system-wide | sudo bash 7 | ``` 8 | 9 | ### Local (User) Deployment 10 | 11 | ```sh 12 | curl -L https://raw.githubusercontent.com/fnichol/bashrc/master/contrib/install-local | bash 13 | ``` 14 | 15 | ### Delay Loading Your Local Deployment 16 | Simply wrap the code in your `${HOME}/.bash_profile` with a function, like so: 17 | 18 | ```sh 19 | bl() { 20 | if [[ -s "${HOME}/.bash/bashrc" ]] ; then 21 | bashrc_local_install=1 22 | bashrc_prefix="${HOME}/.bash" 23 | export bashrc_local_install bashrc_prefix 24 | source "${bashrc_prefix}/bashrc" 25 | fi 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /bashrc.local.site: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------- 2 | # Local (system) bashrc File 3 | #--------------------------------------------------------------- 4 | 5 | # Skip this config if we aren't in bash 6 | [[ -n "${BASH_VERSION}" ]] || return 7 | 8 | #--------------------------------------------------------------- 9 | # Set Global Environment Variables 10 | #--------------------------------------------------------------- 11 | #RUBY_MANAGER= 12 | 13 | 14 | #--------------------------------------------------------------- 15 | # Set Host Prompt Color 16 | #--------------------------------------------------------------- 17 | # The following color keywords are permitted: 18 | # 19 | # Normal colors 20 | # black red green yellow blue magenta cyan white default 21 | # 22 | # Emphasized (bolded) colors 23 | # eblack ered egreen eyellow eblue emagenta ecyan ewhite 24 | #--------------------------------------------------------------- 25 | #PROMPT_COLOR= 26 | 27 | # If you want a different prompt color when logged in over SSH 28 | #REMOTE_PROMPT_COLOR= 29 | 30 | 31 | #--------------------------------------------------------------- 32 | # Host ssh aliases 33 | #--------------------------------------------------------------- 34 | #alias host="ssh host.domain.com" 35 | -------------------------------------------------------------------------------- /contrib/install-local: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ -d "${HOME}/.bash" ]] ; then 4 | printf "\n>> ${HOME}/.bash must not exist so not installing.\n\n" 5 | exit 2 6 | fi 7 | 8 | if command -v git >/dev/null ; then 9 | printf "===> Cloning git repository to ${HOME}/.bash ...\n" 10 | builtin cd "${HOME}" && \ 11 | ( git clone --depth 1 https://github.com/fnichol/bashrc.git .bash || \ 12 | git clone https://github.com/fnichol/bashrc.git .bash ) 13 | elif command -v curl >/dev/null && command -v python >/dev/null; then 14 | tarball_install=1 15 | case "$(uname -s)" in 16 | SunOS) tar_cmd="$(which gtar)" ;; 17 | *) tar_cmd="$(which tar)" ;; 18 | esac 19 | [[ -z "$tar_cmd" ]] && \ 20 | printf ">>>> tar command not found on path, aborting.\n" && exit 13 21 | 22 | printf "===> Git not found, so downloading tarball to ${HOME}/.bash ...\n" 23 | mkdir -p "${HOME}/.bash" 24 | curl -LsSf https://github.com/fnichol/bashrc/tarball/master | \ 25 | ${tar_cmd} xvz -C${HOME}/.bash --strip 1 26 | printf "===> Determining version date from github api ...\n" 27 | tip_date="$(curl -sSL \ 28 | http://github.com/api/v2/json/commits/show/fnichol/bashrc/HEAD | \ 29 | python -c 'import sys; import json; j = json.loads(sys.stdin.read()); print j["commit"]["committed_date"];')" 30 | if [ "$?" -ne 0 ] ; then tip_date="UNKNOWN" ; fi 31 | printf "TARBALL $tip_date" > "${HOME}/.bash/tip.date" 32 | else 33 | printf "\n>> Neither git nor curl (with python) could be found on path so not installing.\n\n" 34 | exit 3 35 | fi 36 | 37 | printf "===> Running bashrc init ...\n" 38 | bash -c "bashrc_local_install=1; bashrc_prefix=\"\${HOME}/.bash\"; source \${bashrc_prefix}/bashrc && bashrc init" 39 | -------------------------------------------------------------------------------- /contrib/install-system-wide: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ "$(whoami)" != "root" ]] ; then 4 | printf "\nYou must be root to run this installer. Either become root, or try sudo/pfexec.\n\n" 5 | exit 1 6 | fi 7 | 8 | if [[ -d "/etc/bash" ]] ; then 9 | printf "\n>> /etc/bash must not exist so not installing.\n\n" 10 | exit 2 11 | fi 12 | 13 | if command -v git >/dev/null ; then 14 | printf "===> Cloning git repository to /etc/bash ...\n" 15 | builtin cd "/etc" && \ 16 | ( git clone --depth 1 https://github.com/fnichol/bashrc.git bash || \ 17 | git clone https://github.com/fnichol/bashrc.git bash ) 18 | elif command -v curl >/dev/null && command -v python >/dev/null; then 19 | tarball_install=1 20 | case "$(uname -s)" in 21 | SunOS) tar_cmd="$(which gtar)" ;; 22 | *) tar_cmd="$(which tar)" ;; 23 | esac 24 | [[ -z "$tar_cmd" ]] && \ 25 | printf ">>>> tar command not found on path, aborting.\n" && exit 13 26 | 27 | printf "===> Git not found, so downloading tarball to /etc/bash ...\n" 28 | mkdir -p "/etc/bash" 29 | curl -LsSf https://github.com/fnichol/bashrc/tarball/master | \ 30 | ${tar_cmd} xvz -C/etc/bash --strip 1 31 | printf "===> Determining version date from github api ...\n" 32 | tip_date="$(curl -sSL \ 33 | http://github.com/api/v2/json/commits/show/fnichol/bashrc/HEAD | \ 34 | python -c 'import sys; import json; j = json.loads(sys.stdin.read()); print j["commit"]["committed_date"];')" 35 | if [ "$?" -ne 0 ] ; then tip_date="UNKNOWN" ; fi 36 | printf "TARBALL $tip_date" > "/etc/bash/tip.date" 37 | else 38 | printf "\n>> Neither git nor curl (with python) could be found on path so not installing.\n\n" 39 | exit 3 40 | fi 41 | 42 | printf "===> Running bashrc init ...\n" 43 | bash -c "source /etc/bash/bashrc && bashrc init" 44 | -------------------------------------------------------------------------------- /bashrc: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------- 2 | # Global bashrc File 3 | #--------------------------------------------------------------- 4 | 5 | # Skip this config if we aren't in bash 6 | [[ -n "${BASH_VERSION}" ]] || return 7 | 8 | # Skip this config if has already loaded 9 | if declare -f __bashrc_reload >/dev/null && [[ ${bashrc_reload_flag:-0} -eq 0 ]] 10 | then 11 | return 12 | fi 13 | 14 | [[ -n "${bashrc_prefix}" ]] && export bashrc_prefix 15 | 16 | 17 | #--------------------------------------------------------------- 18 | # Define Default System Paths 19 | #--------------------------------------------------------------- 20 | 21 | ## 22 | # Removes all instances of paths in a search path. 23 | # 24 | # @param [String] path variable to manipulate (ex: PATH, PYTHONPATH, etc) 25 | # @param [List] space-seperated list of system paths to remove 26 | __remove_from_path() { 27 | local path_var="$1" 28 | shift 29 | local new_path="" 30 | 31 | case "$_os" in 32 | SunOS) 33 | local tr_cmd=/usr/gnu/bin/tr 34 | local grep_cmd=/usr/gnu/bin/grep 35 | local sed_cmd=/usr/gnu/bin/sed 36 | ;; 37 | OpenBSD) 38 | local tr_cmd=/usr/bin/tr 39 | local grep_cmd=/usr/bin/grep 40 | local sed_cmd=/usr/bin/sed 41 | ;; 42 | *) 43 | local tr_cmd=tr 44 | local grep_cmd=grep 45 | local sed_cmd=sed 46 | ;; 47 | esac 48 | 49 | # remove paths from path_var, working in new_path 50 | for rp in $@ ; do 51 | new_path="$(eval "echo \"\$$path_var\"" | $tr_cmd ':' '\n' | \ 52 | $grep_cmd -v "^${rp}$" | $tr_cmd '\n' ':' | $sed_cmd -e 's/:$//')" 53 | done ; unset rp 54 | 55 | # reassign path_var from new_path 56 | eval "$path_var='$new_path'" 57 | } 58 | 59 | ## 60 | # Sets a colon-seperated search path variable, overwriting any previous values. 61 | # 62 | # @param [String] path variable to manipulate (ex: PATH, PYTHONPATH, etc) 63 | # @param [List] space-seperated list of system paths to append, in order 64 | __set_path() { 65 | local path_var="$1" 66 | shift 67 | 68 | # set var and overwrite any previous values 69 | [[ -d "$1" ]] && eval $path_var="$1" 70 | shift 71 | 72 | for p in $@ ; do 73 | __remove_from_path "$path_var" "$p" 74 | [[ -d "$p" ]] && eval $path_var="\$${path_var}:${p}" 75 | done ; unset p 76 | } 77 | 78 | ## 79 | # Appends paths to the end of a search path variable list. 80 | # 81 | # @param [String] path variable to manipulate (ex: PATH, PYTHONPATH, etc) 82 | # @param [List] space-seperated list of system paths to append, in order 83 | __append_path() { 84 | local path_var="$1" 85 | shift 86 | 87 | # create var if not exists 88 | if eval "test -z \"\$$path_var\"" ; then 89 | [[ -d "$1" ]] && eval $path_var="$1" 90 | shift 91 | fi 92 | 93 | for p in $@ ; do 94 | __remove_from_path "$path_var" "$p" 95 | [[ -d "$p" ]] && eval $path_var="\$${path_var}:${p}" 96 | done ; unset p 97 | } 98 | 99 | ## 100 | # Pushes paths to the front of a search path variable list. 101 | # 102 | # @param [String] path variable to manipulate (ex: PATH, PYTHONPATH, etc) 103 | # @param [List] space-seperated list of system paths to push, in reverse order 104 | __push_path() { 105 | local path_var="$1" 106 | shift 107 | 108 | # create var if not exists 109 | if eval "test -z \"\$$path_var\"" ; then 110 | [[ -d "$1" ]] && eval $path_var="$1" 111 | shift 112 | fi 113 | 114 | for p in $@ ; do 115 | __remove_from_path "$path_var" "$p" 116 | [[ -d "$p" ]] && eval $path_var="${p}:\$${path_var}" 117 | done ; unset p 118 | } 119 | 120 | # Determines the machine _os to set PATH, MANPATH and _id 121 | _os="$(uname -s)" 122 | case "$_os" in 123 | Linux) # Linux 124 | __push_path PATH /opt/*/current/bin 125 | 126 | _id=/usr/bin/id 127 | if [[ -n "${bashrc_local_install}" ]] || [[ $($_id -u) -eq 0 ]] ; then 128 | super_cmd() { 129 | "$@" 130 | } 131 | else 132 | super_cmd() { 133 | /usr/bin/sudo -p "[sudo] password for %u@$(hostname): " "$@" 134 | } 135 | fi 136 | if [ -f "/etc/redhat-release" ] ; then 137 | LINUX_FLAVOR="$(awk '{print $1}' /etc/redhat-release)" 138 | fi 139 | if [ -f "/etc/lsb-release" ] ; then 140 | LINUX_FLAVOR="$(head -n 1 /etc/lsb-release | awk -F= '{print $2}')" 141 | fi 142 | ;; 143 | Darwin) # Mac OS X 144 | __push_path PATH /opt/local/sbin /opt/local/bin /opt/*/current/bin \ 145 | /usr/local/share/python "$HOME"/Library/Python/*/bin \ 146 | /opt/homebrew/sbin /opt/homebrew/bin \ 147 | /usr/local/sbin /usr/local/bin 148 | __push_path MANPATH /opt/local/man /usr/local/share/man 149 | 150 | # if we can determine the version of java as set in java prefs, then export 151 | # JAVA_HOME to match this 152 | [[ -s "/usr/libexec/java_home" ]] && export JAVA_HOME=$(/usr/libexec/java_home) 153 | 154 | _id=/usr/bin/id 155 | if [[ -n "${bashrc_local_install}" ]] || [[ $($_id -u) -eq 0 ]] ; then 156 | super_cmd() { 157 | "$@" 158 | } 159 | else 160 | super_cmd() { 161 | /usr/bin/sudo -p "[sudo] password for %u@$(hostname): " "$@" 162 | } 163 | fi 164 | ;; 165 | OpenBSD) # OpenBSD 166 | # Set a base PATH based on original /etc/skel/.profile and /root/.profile 167 | # from 4.6 on 2010-01-01 168 | __set_path PATH /sbin /usr/sbin /bin /usr/bin /usr/X11R6/bin \ 169 | /usr/local/sbin /usr/local/bin 170 | 171 | # OpenBSD now uses `doas` as the default in favor of sudo 172 | _id=/usr/bin/id 173 | if [[ -n "${bashrc_local_install}" ]] || [[ $($_id -u) -eq 0 ]] ; then 174 | super_cmd() { 175 | "$@" 176 | } 177 | else 178 | super_cmd() { 179 | /usr/bin/doas "$@" 180 | } 181 | fi 182 | ;; 183 | FreeBSD) # FreeBSD 184 | _id=/usr/bin/id 185 | if [[ -n "${bashrc_local_install}" ]] || [[ $($_id -u) -eq 0 ]] ; then 186 | super_cmd() { 187 | "$@" 188 | } 189 | else 190 | super_cmd() { 191 | /usr/local/bin/sudo -p "[sudo] password for %u@$(hostname): " "$@" 192 | } 193 | fi 194 | ;; 195 | SunOS) # Solaris 196 | case "$(uname -r)" in 197 | "5.11") # OpenSolaris 198 | __set_path PATH /opt/*/current/bin /opt/local/sbin /opt/local/bin \ 199 | /usr/local/sbin /usr/local/bin /usr/gnu/bin \ 200 | /usr/sbin /sbin /usr/bin /usr/X11/bin 201 | 202 | __set_path MANPATH /usr/gnu/share/man /usr/share/man /usr/X11/share/man 203 | 204 | _id=/usr/bin/id 205 | if [[ -n "${bashrc_local_install}" ]] || [[ $($_id -u) -eq 0 ]] ; then 206 | super_cmd() { 207 | "$@" 208 | } 209 | else 210 | super_cmd() { 211 | /usr/bin/pfexec "$@" 212 | } 213 | fi 214 | 215 | # Files you make look like rw-r--r-- 216 | umask 022 217 | 218 | # Make less the default pager 219 | export PAGER="/usr/bin/less -ins" 220 | ;; 221 | "5.10") # Solaris 10 222 | # admin path 223 | __set_path PATH /opt/local/sbin /usr/gnu/sbin /usr/local/sbin \ 224 | /usr/platform/$(uname -i)/sbin /sbin /usr/sbin 225 | # general path 226 | __append_path PATH /opt/local/bin /usr/gnu/bin /usr/local/bin \ 227 | /bin /usr/bin /usr/ccs/bin /usr/openwin/bin /usr/dt/bin \ 228 | /opt/sun/bin /opt/SUNWspro/bin /opt/SUNWvts/bin 229 | 230 | __append_path MANPATH /opt/local/share/man /usr/gnu/man \ 231 | /usr/local/man /usr/man /usr/share/man /opt/SUNWspro/man \ 232 | /opt/SUNWvts/man 233 | 234 | _id=/usr/xpg4/bin/id 235 | if [[ -n "${bashrc_local_install}" ]] || [[ $($_id -u) -eq 0 ]] ; then 236 | super_cmd() { 237 | "$@" 238 | } 239 | else 240 | super_cmd() { 241 | /usr/bin/pfexec "$@" 242 | } 243 | fi 244 | 245 | # build python search path, favoring newer pythons over older ones 246 | for ver in 2.7 2.6 2.5 2.4 ; do 247 | __append_path PYTHONPATH /usr/local/lib/python${ver}/site-packages 248 | done ; unset ver 249 | [[ -n "$PYTHONPATH" ]] && export PYTHONPATH 250 | 251 | # Files you make look like rw-r--r-- 252 | umask 022 253 | 254 | # Make less the default pager 255 | if command -v less >/dev/null ; then 256 | export PAGER="$(command -v less)" 257 | fi 258 | 259 | unset ADMINPATH 260 | ;; 261 | esac 262 | ;; 263 | CYGWIN_*) # Windows running Cygwin 264 | _id=/usr/bin/id 265 | super_cmd() { 266 | "$@" 267 | } 268 | ;; 269 | esac # uname -s 270 | 271 | 272 | # If a $HOME/bin directory exists, add it to the PATH in front 273 | __push_path PATH $HOME/bin 274 | 275 | # If a $HOME/.local/bin directory exists, add it to the PATH in front 276 | __push_path PATH $HOME/.local/bin 277 | 278 | # If a $HOME/.cargo/bin directory exists, add it to the PATH in front 279 | __push_path PATH $HOME/.cargo/bin 280 | 281 | # If a $HOME/.volta/bin directory exists, add it to the PATH in front 282 | __push_path PATH $HOME/.volta/bin 283 | 284 | # If a $HOME/.luarocks/bin directory exists, add it to the PATH in front 285 | __push_path PATH $HOME/.luarocks/bin 286 | 287 | # If a /usr/local/go/bin directory exists, add it to the PATH in front 288 | __push_path PATH /usr/local/go/bin 289 | 290 | # If a $HOME/man directory exists, add it to the MANPATH in front 291 | __push_path MANPATH $HOME/man 292 | 293 | case "$_os" in 294 | OpenBSD) 295 | # make sure MANPATH isn't set 296 | unset MANPATH 297 | ;; 298 | *) 299 | export MANPATH 300 | ;; 301 | esac # uname -s 302 | 303 | export PATH super_cmd 304 | 305 | if [[ -x "$HOME/.volta/bin/volta" ]]; then 306 | export VOLTA_HOME="$HOME/.volta" 307 | fi 308 | 309 | if [[ -r "${bashrc_prefix:-/etc/bash}/bashrc.local" ]] ; then 310 | source "${bashrc_prefix:-/etc/bash}/bashrc.local" 311 | fi 312 | 313 | if [[ -z "$_debug_bashrc" ]] ; then 314 | unset __set_path __append_path __push_path __remove_from_path 315 | fi 316 | 317 | 318 | #--------------------------------------------------------------- 319 | # Functions 320 | #--------------------------------------------------------------- 321 | 322 | ## 323 | # Unsets any outstanding environment variables and unsets itself. 324 | # 325 | cleanup() { 326 | unset PROMPT_COLOR REMOTE_PROMPT_COLOR _os _id bashrc_reload_flag 327 | unset cleanup 328 | } 329 | 330 | ## 331 | # Takes json on stdin and prints the value of a given path on stdout. 332 | # 333 | # @param [String] json path in the form of ["one"]["two"] 334 | json_val() { 335 | [[ -z "$1" ]] && printf "Usage: json_val \n" && return 10 336 | 337 | local python; 338 | if command -v python3; then 339 | python=python3 340 | else 341 | python=python 342 | fi 343 | 344 | "$python" -c 'import sys; import json; \ 345 | j = json.loads(sys.stdin.read()); \ 346 | print(j'$1');' 347 | } 348 | 349 | ## 350 | # Checks if there any upstream updates. 351 | # 352 | # @param -q suppress output 353 | # @return 0 if up to date, 1 if there are updates, and 5 if there are errors 354 | __bashrc_check() { 355 | if [ "$1" == "-q" ] ; then local suppress=1 && shift ; fi 356 | 357 | local prefix="${bashrc_prefix:-/etc/bash}" 358 | 359 | if [ ! -f "${prefix}/tip.date" ] ; then 360 | printf ">>> File ${prefix}/tip.date does not exist so cannot check.\n" 361 | return 5 362 | fi 363 | 364 | local tip_date=$(cat ${prefix}/tip.date) 365 | local flavor=${tip_date%% *} 366 | 367 | case "$flavor" in 368 | TARBALL) 369 | if command -v curl >/dev/null && command -v python >/dev/null ; then 370 | local last_commit_date="$(curl -sSL \ 371 | http://github.com/api/v2/json/commits/show/fnichol/bashrc/HEAD | \ 372 | json_val '["commit"]["committed_date"]')" 373 | if [ "${tip_date#* }" == "$last_commit_date" ] ; then 374 | [[ -z "$suppress" ]] && printf -- "-----> bashrc is up to date.\n" 375 | return 0 376 | else 377 | [[ -z "$suppress" ]] && \ 378 | printf -- "-----> bashrc has updates to download." && \ 379 | printf " Use 'bashrc update' to get current.\n" 380 | return 1 381 | fi 382 | else 383 | [[ -z "$suppress" ]] && \ 384 | printf ">>>> Can't find curl and/or python commands.\n" 385 | return 5 386 | fi 387 | ;; 388 | *) 389 | if command -v git >/dev/null ; then 390 | (cd $prefix && super_cmd git fetch --quiet 2>&1 >/dev/null) 391 | (cd $prefix && super_cmd git --no-pager diff --quiet --exit-code \ 392 | --no-color master..origin/master >/dev/null) 393 | if [[ "$?" -eq 0 ]] ; then 394 | [[ -z "$suppress" ]] && printf -- "-----> bashrc is up to date.\n" 395 | return 0 396 | else 397 | [[ -z "$suppress" ]] && \ 398 | printf -- "-----> bashrc has updates to download." && \ 399 | printf " Use 'bashrc update' to get current.\n" 400 | return 1 401 | fi 402 | else 403 | [[ -z "$suppress" ]] && printf ">>>> Can't find git command.\n" 404 | return 5 405 | fi 406 | ;; 407 | esac 408 | } 409 | 410 | ## 411 | # Initializes bashrc profile 412 | __bashrc_init() { 413 | local prefix="${bashrc_prefix:-/etc/bash}" 414 | 415 | local egrep_cmd= 416 | case "$(uname -s)" in 417 | SunOS) egrep_cmd=/usr/gnu/bin/egrep ;; 418 | *) egrep_cmd=egrep ;; 419 | esac 420 | 421 | if [[ -f "${prefix}/bashrc.local" ]] ; then 422 | printf "A pre-existing ${prefix}/bashrc.local file was found, using it\n" 423 | else 424 | printf -- "-----> Creating ${prefix}/bashrc.local ...\n" 425 | super_cmd cp "${prefix}/bashrc.local.site" "${prefix}/bashrc.local" 426 | 427 | local color= 428 | case "$(uname -s)" in 429 | Darwin) color="green" ; local remote_color="yellow" ;; 430 | Linux) color="cyan" ;; 431 | OpenBSD) color="red" ;; 432 | FreeBSD) color="magenta" ;; 433 | CYGWIN*) color="black" ;; 434 | SunOS) 435 | if /usr/sbin/zoneadm list -pi | $egrep_cmd :global: >/dev/null ; then 436 | color="magenta" # root zone 437 | else 438 | color="cyan" # non-global zone 439 | fi 440 | ;; 441 | esac 442 | 443 | printf "Setting prompt color to be \"$color\" ...\n" 444 | super_cmd sed -i"" -e "s|^#\{0,1\}PROMPT_COLOR=.*$|PROMPT_COLOR=$color|g" \ 445 | "${prefix}/bashrc.local" 446 | unset color 447 | 448 | if [[ -n "$remote_color" ]] ; then 449 | printf "Setting remote prompt color to be \"$remote_color\" ...\n" 450 | super_cmd sed -i"" -e \ 451 | "s|^#\{0,1\}REMOTE_PROMPT_COLOR=.*$|REMOTE_PROMPT_COLOR=$remote_color|g" \ 452 | "${prefix}/bashrc.local" 453 | unset remote_color 454 | fi 455 | fi 456 | 457 | if [[ -n "$bashrc_local_install" ]] ; then 458 | local p="${HOME}/.bash_profile" 459 | 460 | if [[ -r "$p" ]] && $egrep_cmd -q '${HOME}/.bash/bashrc' $p 2>&1 >/dev/null ; then 461 | printf ">> Mention of \${HOME}/.bash/bashrc found in \"$p\"\n" 462 | printf ">> You can add the following lines to get sourced:\n" 463 | printf ">> if [[ -s \"\${HOME}/.bash/bashrc\" ]] ; then\n" 464 | printf ">> bashrc_local_install=1\n" 465 | printf ">> bashrc_prefix=\${HOME}/.bash\n" 466 | printf ">> export bashrc_local_install bashrc_prefix\n" 467 | printf ">> source \"\${bashrc_prefix}/bashrc\"\n" 468 | printf ">> fi\n" 469 | else 470 | printf -- "-----> Adding source hook into \"$p\" ...\n" 471 | cat >> $p <>>> Don't know how to add source hook in this operating system.\n" 502 | return 4 503 | ;; 504 | esac 505 | 506 | if $egrep_cmd -q '/etc/bash/bashrc' $p 2>&1 >/dev/null ; then 507 | printf ">> Mention of /etc/bash/bashrc found in \"$p\"\n" 508 | printf ">> You can add the following line to get sourced:\n" 509 | printf ">> [[ -s \"/etc/bash/bashrc\" ]] && . \"/etc/bash/bashrc\"" 510 | else 511 | printf -- "-----> Adding source hook into \"$p\" ...\n" 512 | cat </dev/null 513 | 514 | [[ -s "/etc/bash/bashrc" ]] && . "/etc/bash/bashrc" 515 | END_OF_PROFILE 516 | fi 517 | fi 518 | unset p 519 | 520 | printf "\n\n" 521 | printf " #---------------------------------------------------------------\n" 522 | printf " # Installation of bashrc complete. To activate either exit\n" 523 | printf " # this shell or type: 'source ${prefix}/bashrc'.\n" 524 | printf " #\n" 525 | printf " # To check for updates to bashrc, run: 'bashrc check'.\n" 526 | printf " #\n" 527 | printf " # To keep bashrc up to date, periodically run: 'bashrc update'.\n" 528 | printf " #---------------------------------------------------------------\n\n" 529 | } 530 | 531 | ## 532 | # Pulls down new changes to the bashrc via git. 533 | __bashrc_update() { 534 | local prefix="${bashrc_prefix:-/etc/bash}" 535 | local repo="github.com/fnichol/bashrc.git" 536 | 537 | # clear out old tarball install or legacy hg cruft 538 | local stash= 539 | if [ ! -d "$prefix/.git" ] ; then 540 | # save a copy of bashrc.local 541 | if [[ -f "$prefix/bashrc.local" ]] ; then 542 | stash="/tmp/bashrc.local.$$" 543 | super_cmd cp -p "$prefix/bashrc.local" "$stash" 544 | fi 545 | super_cmd rm -rf "$prefix" 546 | fi 547 | 548 | if [[ -d "$prefix/.git" ]] ; then 549 | if command -v git >/dev/null ; then 550 | ( builtin cd "$prefix" && super_cmd git pull --rebase origin master ) 551 | else 552 | printf "\n>>>> Command 'git' not found on the path, please install a" 553 | printf " packge or build git from source and try again.\n\n" 554 | return 10 555 | fi 556 | elif command -v git >/dev/null ; then 557 | ( builtin cd "$(dirname $prefix)" && \ 558 | super_cmd git clone --depth 1 https://$repo $(basename $prefix) || \ 559 | super_cmd git clone https://$repo $(basename $prefix) ) 560 | elif command -v curl >/dev/null && command -v python >/dev/null; then 561 | local tarball_install=1 562 | case "$(uname -s)" in 563 | SunOS) local tar_cmd="$(which gtar)" ;; 564 | *) local tar_cmd="$(which tar)" ;; 565 | esac 566 | [[ -z "$tar_cmd" ]] && \ 567 | printf ">>>> tar command not found on path, aborting.\n" && return 13 568 | 569 | printf -- "-----> Git not found, so downloading tarball to $prefix ...\n" 570 | super_cmd mkdir -p "$prefix" 571 | curl -LsSf https://github.com/fnichol/bashrc/tarball/master | \ 572 | super_cmd ${tar_cmd} xvz -C${prefix} --strip 1 573 | else 574 | printf "\n>>>> Command 'git', 'curl', or 'python' were not found on the path, please install a packge or build these packages from source and try again.\n\n" 575 | return 16 576 | fi 577 | local result="$?" 578 | 579 | # move bashrc.local back 580 | [[ -n "$stash" ]] && super_cmd mv "$stash" "$prefix/bashrc.local" 581 | 582 | if [ "$result" -ne 0 ]; then 583 | printf "\n>>>> bashrc could not find an update or has failed.\n\n" 584 | return 11 585 | fi 586 | 587 | if [[ -n "$tarball_install" ]] ; then 588 | 589 | printf -- "-----> Determining version date from github api ...\n" 590 | local tip_date="$(curl -sSL \ 591 | http://github.com/api/v2/json/commits/show/fnichol/bashrc/HEAD | \ 592 | python -c 'import sys; import json; j = json.loads(sys.stdin.read()); print j["commit"]["committed_date"];')" 593 | if [ "$?" -ne 0 ] ; then tip_date="UNKNOWN" ; fi 594 | super_cmd bash -c "(printf \"TARBALL $tip_date\" > \"${prefix}/tip.date\")" 595 | __bashrc_reload 596 | printf -- "\n\n-----> bashrc was updated and reloaded.\n" 597 | else 598 | 599 | local old_file="/tmp/bashrc.date.$$" 600 | if [[ -f "$prefix/tip.date" ]] ; then 601 | super_cmd mv "$prefix/tip.date" "$old_file" 602 | else 603 | touch "$old_file" 604 | fi 605 | 606 | local git_cmd=$(which git) 607 | super_cmd bash -c "( builtin cd $prefix && \ 608 | $git_cmd log -1 --pretty=\"format:%h %ci\" > $prefix/tip.date)" 609 | 610 | if ! diff -q "$old_file" "$prefix/tip.date" >/dev/null ; then 611 | local old_rev=$(awk '{print $1}' $old_file) 612 | local new_rev=$(awk '{print $1}' $prefix/tip.date) 613 | printf "\n#### Updates ####\n-----------------\n" 614 | ( builtin cd $prefix && super_cmd git --no-pager log \ 615 | --pretty=format:'%C(yellow)%h%Creset - %s %Cgreen(%cr)%Creset' \ 616 | --abbrev-commit --date=relative $old_rev..$new_rev ) 617 | printf "\n-----------------\n\n" 618 | __bashrc_reload 619 | printf -- "\n\n-----> bashrc was updated and reloaded.\n" 620 | else 621 | printf -- "\n-----> bashrc is already up to date and current.\n" 622 | fi 623 | 624 | super_cmd rm -f "$old_file" 625 | fi 626 | 627 | if [[ -z "$(cat $prefix/tip.date)" ]] ; then 628 | super_cmd rm -f "$prefix/tip.date" 629 | fi 630 | } 631 | 632 | ## 633 | # Reloads bashrc profile 634 | __bashrc_reload() { 635 | bashrc_reload_flag=1 636 | printf "\n" # give bashrc source line more prominence 637 | source "${bashrc_prefix:-/etc/bash}/bashrc" 638 | printf -- "-----> bashrc was reload at $(date +%F\ %T\ %z).\n" 639 | unset bashrc_reload_flag 640 | } 641 | 642 | ## 643 | # Displays the version of the bashrc profile 644 | __bashrc_version() { 645 | local ver= 646 | # Echo the version and date of the profile 647 | if [[ -f "${bashrc_prefix:-/etc/bash}/tip.date" ]] ; then 648 | ver="$(cat ${bashrc_prefix:-/etc/bash}/tip.date)" 649 | elif command -v git >/dev/null ; then 650 | ver="$(cd ${bashrc_prefix:-/etc/bash} && \ 651 | git log -1 --pretty='format:%h %ci')" 652 | else 653 | ver="UNKNOWN" 654 | fi 655 | printf "bashrc ($ver)\n\n" 656 | } 657 | 658 | ## 659 | # CLI for the bash profile. 660 | bashrc() { 661 | local command="$1" 662 | shift 663 | 664 | case "$command" in 665 | check) __bashrc_check $@;; 666 | init) __bashrc_init $@;; 667 | reload) __bashrc_reload $@;; 668 | update) __bashrc_update $@;; 669 | version) __bashrc_version $@;; 670 | *) printf "usage: bashrc (check|init|reload|update|version)\n" && return 10 ;; 671 | esac 672 | } 673 | 674 | # Skip the rest if this is not an interactive shell 675 | if [ -z "${PS1}" -a "$-" != "*i*" ] ; then cleanup ; return ; fi 676 | 677 | ## 678 | # Sources all existing files in a list of files. Every file that is readable 679 | # will get sourced as a shorthand to listing many lines of safe_source. 680 | # 681 | # Thanks to: https://github.com/darkhelmet/dotfiles for inspiration. 682 | # 683 | # @param [List] space-separated list of source files 684 | safe_source() { 685 | for src ; do 686 | [[ -r "$src" ]] && source "$src" 687 | done ; unset src 688 | } 689 | 690 | ## 691 | # Sources first existing file in a list of files. Only the first match will be 692 | # sourced which emulates as if/elsif/elsif... structure. 693 | # 694 | # Thanks to: https://github.com/darkhelmet/dotfiles for inspiration. 695 | # 696 | # @param [List] space-separated list of source files 697 | safe_source_first() { 698 | for src ; do 699 | [[ -r "$src" ]] && source "$src" && unset src && return 700 | done ; unset src 701 | } 702 | 703 | ## 704 | # Prints terminal codes. 705 | # 706 | # Thanks to: http://github.com/wayneeseguin/rvm/blob/master/scripts/color 707 | # 708 | # @param [String] terminal code keyword (usually a color) 709 | bput() { 710 | case "$1" in 711 | # regular colors 712 | black) tput setaf 0 ;; 713 | red) tput setaf 1 ;; 714 | green) tput setaf 2 ;; 715 | yellow) tput setaf 3 ;; 716 | blue) tput setaf 4 ;; 717 | magenta) tput setaf 5 ;; 718 | cyan) tput setaf 6 ;; 719 | white) tput setaf 7 ;; 720 | 721 | # emphasized (bolded) colors 722 | eblack) tput bold ; tput setaf 0 ;; 723 | ered) tput bold ; tput setaf 1 ;; 724 | egreen) tput bold ; tput setaf 2 ;; 725 | eyellow) tput bold ; tput setaf 3 ;; 726 | eblue) tput bold ; tput setaf 4 ;; 727 | emagenta) tput bold ; tput setaf 5 ;; 728 | ecyan) tput bold ; tput setaf 6 ;; 729 | ewhite) tput bold ; tput setaf 7 ;; 730 | 731 | # underlined colors 732 | ublack) set smul unset rmul ; tput setaf 0 ;; 733 | ured) set smul unset rmul ; tput setaf 1 ;; 734 | ugreen) set smul unset rmul ; tput setaf 2 ;; 735 | uyellow) set smul unset rmul ; tput setaf 3 ;; 736 | ublue) set smul unset rmul ; tput setaf 4 ;; 737 | umagenta) set smul unset rmul ; tput setaf 5 ;; 738 | ucyan) set smul unset rmul ; tput setaf 6 ;; 739 | uwhite) set smul unset rmul ; tput setaf 7 ;; 740 | 741 | # background colors 742 | bblack) tput setab 0 ;; 743 | bred) tput setab 1 ;; 744 | bgreen) tput setab 2 ;; 745 | byellow) tput setab 3 ;; 746 | bblue) tput setab 4 ;; 747 | bmagenta) tput setab 5 ;; 748 | bcyan) tput setab 6 ;; 749 | bwhite) tput setab 7 ;; 750 | 751 | # Defaults 752 | default) tput setaf 9 ;; 753 | bdefault) tput setab 9 ;; 754 | none) tput sgr0 ;; 755 | *) tput sgr0 # Reset 756 | esac 757 | } 758 | 759 | ## 760 | # Calculates are truncated pwd. Overriding of the truncation length can be done 761 | # by setting `PROMPT_LEN'. 762 | # 763 | # Thanks to: https://gist.github.com/548242 (@nicksieger) 764 | short_pwd () 765 | { 766 | local pwd_length=${PROMPT_LEN-35} 767 | local cur_pwd=$(echo $(pwd) | sed -e "s,^$HOME,~,") 768 | 769 | if [ $(echo -n $cur_pwd | wc -c | tr -d " ") -gt $pwd_length ]; then 770 | echo "...$(echo $cur_pwd | sed -e "s/.*\(.\{$pwd_length\}\)/\1/")" 771 | else 772 | echo $cur_pwd 773 | fi 774 | } 775 | 776 | ## 777 | # Prints out contextual rvm/git state for the command prompt. 778 | # 779 | # Thanks to https://github.com/darkhelmet/dotfiles for the inspiration. 780 | __prompt_state() { 781 | local git_status= 782 | local git_status_exit=255 783 | local hg_status= 784 | local hg_status_exit=255 785 | 786 | git_status=$(git -c color.status=false status --short --branch 2>/dev/null) 787 | git_status_exit=$? 788 | 789 | if [ $git_status_exit -eq 0 ] ; then 790 | local bits='' 791 | printf "$git_status" | egrep -q '^ ?M' && bits="${bits}±" # modified files 792 | printf "$git_status" | egrep -q '^ ?\?' && bits="${bits}?" # untracked files 793 | printf "$git_status" | egrep -q '^ ?A' && bits="${bits}*" # new/added files 794 | printf "$git_status" | egrep -q '^ ?R' && bits="${bits}>" # renamed files 795 | printf "$git_status" | egrep -q '^ ?D' && bits="${bits}⚡" # deleted files 796 | printf "$git_status" | egrep -q ' \[ahead ' && bits="${bits}+" # ahead of origin 797 | 798 | local branch="$(printf "$git_status" | egrep '^## ' | \ 799 | awk '{print $2}' | sed 's/\.\.\..*$//')" 800 | [[ "$branch" == "Initial commit on master" ]] && branch="nobranch" 801 | 802 | local last_commit=$(git log --pretty=format:'%at' -1 2>/dev/null) 803 | local age="-1" 804 | if [[ -n "$last_commit" ]] ; then 805 | age="$(($(($(date +%s)-last_commit))/60))" # zomg nesting 806 | fi 807 | 808 | local age_color="green" 809 | if [[ "$age" -lt 0 ]] ; then 810 | age_color="cyan" 811 | elif [[ "$age" -gt 60 ]] ; then 812 | age_color="red" 813 | elif [[ "$age" -gt 30 ]] ; then 814 | age_color="yellow" 815 | fi 816 | 817 | # if age is more than 7 days, show in days otherwise minutes 818 | if [[ "$age" -gt 10080 ]] ; then 819 | age="$((age/1440))d" 820 | else 821 | age="${age}m" 822 | fi 823 | 824 | case "$TERM" in 825 | *term | xterm-* | rxvt | screen | screen-* | tmux-*) 826 | age="$(bput $age_color)$age$(bput rst)" 827 | bits="$(bput cyan)$bits$(bput rst)" 828 | ;; 829 | esac 830 | 831 | printf "%b" " $(bput magenta)git(${age}$(bput magenta)|$(bput rst)${branch}${bits}$(bput magenta))$(bput rst)" 832 | else 833 | 834 | # only attempt hg repo checks if git fails (no need to compute both every time) 835 | hg_status=$(hg status --config 'extensions.color=!' 2>/dev/null) 836 | hg_status_exit=$? 837 | fi 838 | 839 | if [ $hg_status_exit -eq 0 ] ; then 840 | local bits='' 841 | printf "$hg_status" | egrep -q '^M ' && bits="${bits}±" # modified files 842 | printf "$hg_status" | egrep -q '^\? ' && bits="${bits}?" # untracked files 843 | printf "$hg_status" | egrep -q '^A ' && bits="${bits}*" # new files 844 | printf "$hg_status" | egrep -q '^! ' && bits="${bits}!" # deleted files 845 | printf "$hg_status" | egrep -q '^R ' && bits="${bits}⚡" # removed files 846 | 847 | local branch="$(hg branch)" 848 | [[ -z "$branch" ]] && branch="nobranch" 849 | 850 | local last_commit=$(hg log -l 1 --template '{date|hgdate}' 2>/dev/null | \ 851 | awk '{print $1}') 852 | local age="-1" 853 | if [[ -n "$last_commit" ]] ; then 854 | age="$(($(($(date +%s)-last_commit))/60))" # zomg nesting 855 | fi 856 | 857 | local age_color="green" 858 | if [[ "$age" -lt 0 ]] ; then 859 | age_color="cyan" 860 | elif [[ "$age" -gt 60 ]] ; then 861 | age_color="red" 862 | elif [[ "$age" -gt 30 ]] ; then 863 | age_color="yellow" 864 | fi 865 | 866 | # if age is more than 7 days, show in days otherwise minutes 867 | if [[ "$age" -gt 10080 ]] ; then 868 | age="$((age/1440))d" 869 | else 870 | age="${age}m" 871 | fi 872 | 873 | case "$TERM" in 874 | *term | xterm-* | rxvt | screen | screen-* | tmux-*) 875 | age="$(bput $age_color)$age$(bput rst)" 876 | bits="$(bput cyan)$bits$(bput rst)" 877 | ;; 878 | esac 879 | 880 | printf "%b" " $(bput magenta)hg(${age}$(bput magenta)|$(bput rst)${branch}${bits}$(bput magenta))$(bput rst)" 881 | fi 882 | 883 | if command -v chruby >/dev/null && [[ -n "$RUBY_ROOT" ]] ; then 884 | printf "%b" " {$(basename $RUBY_ROOT)}" 885 | elif command -v rvm-prompt >/dev/null ; then 886 | printf "%b" " {$(rvm-prompt)}" 887 | fi 888 | } 889 | 890 | ## 891 | # Sets a shell prompt. Uses a set variable of `PROMPT_COLOR' to determine 892 | # the main color of the prompt, if it exists. This is generally set in 893 | # bashrc.local. If a variable of `REMOTE_PROMPT_COLOR' is given, then this 894 | # color will be used for all remote SSH sessions. 895 | # 896 | bash_prompt() { 897 | [[ -z "$PROMPT_COLOR" ]] && PROMPT_COLOR="default" 898 | 899 | # change prompt color if remotely logged in and alt color is given 900 | if [ -n "$SSH_CLIENT" -a -n "$REMOTE_PROMPT_COLOR" ] ; then 901 | PROMPT_COLOR="$REMOTE_PROMPT_COLOR" 902 | fi 903 | 904 | if [ "$($_id -ur)" -eq "0" ] ; then # am I root? 905 | local user_c="#" ; local tb=$user_c ; local color="red" 906 | else 907 | local user_c=">" ; local tb="" ; local color="$PROMPT_COLOR" 908 | fi 909 | 910 | case "$TERM" in 911 | *term | xterm-* | rxvt | screen | screen-* | tmux-*) 912 | local cyan="\[$(bput cyan)\]" 913 | if [[ -z "$bashrc_light_bg" ]] ; then 914 | local white="\[$(bput white)\]" 915 | else 916 | local white="\[$(bput black)\]" 917 | fi 918 | local nocolor="\[$(bput rst)\]" 919 | local custom="\[$(bput $color)\]" 920 | local titlebar="\[\033]0;${tb}\u@\h:\w${tb}\007\]" 921 | ;; 922 | *) 923 | local cyan="" 924 | local white="" 925 | local nocolor="" 926 | local custom="" 927 | local titlebar="" 928 | ;; 929 | esac 930 | 931 | local prompt_core="" 932 | if [ -n "$SSH_TTY" -o "$($_id -ur)" -eq "0" ] ; then 933 | local prompt_core="\u@\h" 934 | fi 935 | 936 | PS1="${titlebar}${cyan}[${custom}\$(short_pwd)${white}\$(__prompt_state)${cyan}]${nocolor}\n${custom}${prompt_core}${user_c} ${nocolor}" 937 | PS2="${custom}${user_c} ${nocolor}" 938 | } 939 | 940 | ## 941 | # Determines the primary hostname of another domain name. Often used to 942 | # resolve a website url (like `www.example.com') to a server hostname 943 | # (like `webserver1.domainhosting.com'). 944 | # 945 | # @params [String] domainname to look up 946 | if command -v dig >/dev/null ; then 947 | hostfromdomain() { 948 | [[ -z "$1" ]] && printf "usage: hostfromdomain \n" && return 11 949 | dig -x $(dig $1 +short) +short 950 | } 951 | fi 952 | 953 | ## 954 | # Places a given public ssh key on a remote host for key-based authentication. 955 | # The host can optionally contain the username (like `jdoe@ssh.example.com') 956 | # and a non-standard port number (like `ssh.example.com:666'). 957 | # 958 | # @param [String] remote ssh host in for form of [@]host[:] 959 | # @param [String] public key, using $HOME/.ssh/id_ed25519.pub by default 960 | authme() { 961 | [[ -z "$1" ]] && printf "Usage: authme []\n" && return 10 962 | 963 | local host="$1" 964 | shift 965 | if [[ -z "$1" ]] ; then 966 | if [[ -f "${HOME}/.ssh/id_ed25519.pub" ]] ; then 967 | local key="${HOME}/.ssh/id_ed25519.pub" 968 | else 969 | local key="${HOME}/.ssh/id_rsa.pub" 970 | fi 971 | else 972 | local key="$1" 973 | fi 974 | shift 975 | 976 | [[ ! -f "$key" ]] && echo "SSH key: $key does not exist." && return 11 977 | 978 | if echo "$host" | egrep -q ':' ; then 979 | local ssh_cmd="$(echo $host | awk -F':' '{print "ssh -p " $2 " " $1}')" 980 | else 981 | local ssh_cmd="ssh $host" 982 | fi 983 | 984 | $ssh_cmd '(if [ ! -d "${HOME}/.ssh" ]; then \ 985 | mkdir -m 0700 -p ${HOME}/.ssh; fi; \ 986 | cat - >> .ssh/authorized_keys)' < $key 987 | } 988 | 989 | ## 990 | # Returns the remote user's public SSH key on STDOUT. The host can optionally 991 | # contain the username (like `jdoe@ssh.example.com') and a non-standard port 992 | # number (like `ssh.example.com:666'). 993 | # 994 | # @param [String] remote ssh host in for form of [@]host[:] 995 | # @param [String] remote public key, using id_ed25519.pub by default 996 | mysshkey() { 997 | [[ -z "$1" ]] && printf "Usage: mysshkey []\n" && return 10 998 | 999 | local host="$1" 1000 | shift 1001 | if [[ -z "$1" ]] ; then 1002 | local key="id_ed25519.pub" 1003 | else 1004 | local key="$1" 1005 | fi 1006 | shift 1007 | 1008 | if echo "$host" | egrep -q ':' ; then 1009 | local ssh_cmd="$(echo $host | awk -F':' '{print \"ssh -p \" $2 \" \" $1}')" 1010 | else 1011 | local ssh_cmd="ssh $host" 1012 | fi 1013 | 1014 | $ssh_cmd "(cat .ssh/$key)" 1015 | } 1016 | 1017 | ## 1018 | # Quickly starts a webserver from the current directory. 1019 | # 1020 | # Thanks to: 1021 | # http://superuser.com/questions/52483/terminal-tips-and-tricks-for-mac-os-x 1022 | # 1023 | # @param [optional, Integer] bind port number, default 8000 1024 | web_serve() { 1025 | local p="${1:-8000}" 1026 | if command -v ruby >/dev/null; then 1027 | ruby -rwebrick \ 1028 | -e"WEBrick::HTTPServer.new(:Port => $p, :DocumentRoot => Dir.pwd).start" 1029 | elif command -v python >/dev/null; then 1030 | python -m SimpleHTTPServer $p 1031 | else 1032 | printf ">>>> Could not find ruby or python on PATH. Install and retry.\n" 1033 | return 9 1034 | fi 1035 | } 1036 | 1037 | ## 1038 | # Launch view using input from STDIN initialized with a desired filetype. 1039 | # 1040 | # @param [String] vim/view filetype, such as `json`, `yaml`, etc. 1041 | viewin() { 1042 | vim -R -c "set ft=$1" - 1043 | } 1044 | 1045 | # 1046 | # Performs an egrep on the process list. Use any arguments that egrep accetps. 1047 | # 1048 | # @param [Array] egrep arguments 1049 | case "$_os" in 1050 | Darwin|OpenBSD|FreeBSD) psg() { ps wwwaux | grep -E "($@|\bPID\b)" | grep -E -v "grep"; } ;; 1051 | SunOS|Linux) psg() { ps -ef | grep -E "($@|\bPID\b)" | grep -E -v "grep"; } ;; 1052 | CYGWIN_*) psg() { ps -efW | grep -E "($@|\bPID\b)" | grep -E -v "grep"; } ;; 1053 | esac 1054 | 1055 | case "$_os" in 1056 | Darwin) 1057 | ## 1058 | # Logs out another logged in macOS user, or the current user by default. 1059 | # 1060 | # Thanks to: 1061 | # https://superuser.com/questions/40061/what-is-the-mac-os-x-terminal-command-to-log-out-the-current-user#answer-1368015 1062 | # 1063 | # @param [optional, String] macOS username, defaulting to current user 1064 | logout-gui() { 1065 | sudo launchctl bootout "user/$(id -u "${1:-$USER}")" 1066 | } 1067 | 1068 | ## 1069 | # Quits OS X applications from the command line. 1070 | # 1071 | # Thanks to: 1072 | # http://superuser.com/questions/52483/terminal-tips-and-tricks-for-mac-os-x 1073 | # 1074 | # @param [List] list of applications 1075 | quit() { 1076 | for app in $* ; do 1077 | osascript -e 'quit app "'$app'"' 1078 | done ; unset app 1079 | } 1080 | 1081 | ## 1082 | # Relaunches OS X applications from the command line. 1083 | # 1084 | # Thanks to: 1085 | # http://superuser.com/questions/52483/terminal-tips-and-tricks-for-mac-os-x 1086 | # 1087 | # @param [List] list of applications 1088 | relaunch() { 1089 | for app in $* ; do 1090 | osascript -e 'quit app "'$app'"' 1091 | sleep 2 1092 | open -a $app 1093 | done ; unset app 1094 | } 1095 | 1096 | ## 1097 | # Opens a man page in Preview.app 1098 | # 1099 | # Thanks to: 1100 | # http://superuser.com/questions/52483/terminal-tips-and-tricks-for-mac-os-x 1101 | # 1102 | # @param [String] man page 1103 | # @param [optional, String] man section 1104 | pman() { 1105 | man -t $@ | open -f -a /Applications/Preview.app 1106 | } 1107 | 1108 | ## 1109 | # Updates the firewall rules to allow `mosh-server` after upgrades. 1110 | # 1111 | # Thanks to: 1112 | # https://github.com/mobile-shell/mosh/issues/898#issuecomment-368566044 1113 | mosh-server-fw-update() { 1114 | local fw=/usr/libexec/ApplicationFirewall/socketfilterfw 1115 | local bin_symlink bin_path 1116 | bin_symlink="$(command -v mosh-server)" 1117 | bin_path="$(greadlink -f "$bin_symlink")" 1118 | 1119 | sudo "$fw" --setglobalstate off 1120 | sudo "$fw" --add "$bin_symlink" 1121 | sudo "$fw" --unblockapp "$bin_symlink" 1122 | sudo "$fw" --add "$bin_path" 1123 | sudo "$fw" --unblockapp "$bin_path" 1124 | sudo "$fw" --setglobalstate on 1125 | } 1126 | ;; 1127 | esac 1128 | 1129 | ## 1130 | # Returns the primary IP address of the system. 1131 | case "$_os" in 1132 | Darwin) 1133 | whatsmy_primary_ip() { 1134 | local _if="$(route -n get default | grep 'interface: ' | awk '{print $2}')" 1135 | local _ip="$(ifconfig $_if | \ 1136 | grep '^[[:space:]]*inet ' | awk '{print $2}')" 1137 | 1138 | if [ -z "$_ip" -o "$_ip" == "" ]; then 1139 | echo "Could not determine primary IP address" 1140 | return 10 1141 | else 1142 | echo $_ip 1143 | fi 1144 | } 1145 | ;; 1146 | OpenBSD|FreeBSD) 1147 | whatsmy_primary_ip() { 1148 | local _if="$(netstat -nr | grep ^default | awk '{print $8}')" 1149 | local _ip="$(ifconfig $_if | \ 1150 | grep '^[[:space:]]*inet ' | awk '{print $2}')" 1151 | 1152 | if [ -z "$_ip" -o "$_ip" == "" ]; then 1153 | echo "Could not determine primary IP address" 1154 | return 10 1155 | else 1156 | echo $_ip 1157 | fi 1158 | } 1159 | ;; 1160 | Linux) 1161 | whatsmy_primary_ip() { 1162 | local _if="$(netstat -nr | grep ^0\.0\.0\.0 | awk '{print $8}')" 1163 | local _ip="$(/sbin/ifconfig $_if | \ 1164 | grep '^[[:space:]]*inet ' | awk '{print $2}' | \ 1165 | awk -F':' '{print $2}')" 1166 | 1167 | if [ -z "$_ip" -o "$_ip" == "" ]; then 1168 | echo "Could not determine primary IP address" 1169 | return 10 1170 | else 1171 | echo $_ip 1172 | fi 1173 | } 1174 | ;; 1175 | SunOS) 1176 | whatsmy_primary_ip() { 1177 | local _def_gateway="$(netstat -nr | grep ^default | \ 1178 | awk '{print $2}')" 1179 | local _if="$(route get $_def_gateway | \ 1180 | grep '^[ ]*interface:' | awk '{print $2}')" 1181 | local _ip="$(ifconfig $_if | \ 1182 | awk '/^\t*inet / {print $2}')" 1183 | 1184 | if [ -z "$_ip" -o "$_ip" == "" ]; then 1185 | echo "Could not determine primary IP address" 1186 | return 10 1187 | else 1188 | echo $_ip 1189 | fi 1190 | } 1191 | ;; 1192 | esac # case $_os 1193 | 1194 | ## 1195 | # Returns the public/internet visible IP address of the system. 1196 | # 1197 | # Thanks to @mojombo's baddass tweet: 1198 | # https://twitter.com/#!/mojombo/status/48948402955882496 1199 | # 1200 | whatsmy_public_ip() { 1201 | curl --silent 'https://jsonip.com/' | json_val '["ip"]' 1202 | } 1203 | 1204 | ## 1205 | # Calculates diskusage (with du) and reports back sorted and human readable. 1206 | # 1207 | # Thanks to https://github.com/lucapette/dotfiles/blob/master/bash/aliases 1208 | # for the inspiration 1209 | # 1210 | # @param [Array] list of files or directories to report on (file args to du) 1211 | diskusage() { 1212 | du -ks "$@" | sort -nr | \ 1213 | awk '{ \ 1214 | if ($1 > 1048576) printf("%8.2fG", $1/1048576) ; \ 1215 | else if ($1 > 1024) printf("%8.2fM", $1/1024) ; \ 1216 | else printf("%8.2fK", $1) ; \ 1217 | sub($1, "") ; print \ 1218 | }' 1219 | } 1220 | 1221 | if [[ ! -f "$HOME/.homesick/repos/homeshick/homeshick.sh" ]]; then 1222 | homeshick_install() { 1223 | if command -v git >/dev/null ; then 1224 | git clone git://github.com/andsens/homeshick.git \ 1225 | "$HOME/.homesick/repos/homeshick" 1226 | safe_source "$HOME/.homesick/repos/homeshick/homeshick.sh" 1227 | unset homeshick_install 1228 | printf -- "-----> homeshick installed and loaded.\n" 1229 | else 1230 | printf ">>>> Could not find git command on PATH. Install and retry.\n" 1231 | return 70 1232 | fi 1233 | } 1234 | fi 1235 | 1236 | if command -v fd >/dev/null && command -v fzf >/dev/null; then 1237 | ## 1238 | # Changes directory based on a fuzzy finder list of directories 1239 | # 1240 | # @param [optional, String] directory path to search under, default `.` 1241 | cf() { 1242 | cd "$(fd --hidden --no-ignore --type d . "${1:-.}" | fzf)" 1243 | } 1244 | fi 1245 | 1246 | ## 1247 | # Prints a timestamp in RFC3339/ISO8601 format, in UTC 1248 | # 1249 | # In other words, a timestamp of the form: `YYYY-mm-ddTHH:MM:SSZ` or 1250 | # `2006-01-02T15:04:05` 1251 | timestamp() { 1252 | date -u +%FT%TZ 1253 | } 1254 | 1255 | 1256 | #--------------------------------------------------------------- 1257 | # Interactive shell (prompt,history) settings 1258 | #--------------------------------------------------------------- 1259 | 1260 | # Set the default editor 1261 | if [ -z "$SSH_CLIENT" ] ; then # for local/console sessions 1262 | case "$TERM" in 1263 | screen*|xterm-256color) # we're in screen or tmux 1264 | if command -v vim >/dev/null ; then 1265 | export EDITOR="$(which vim)" 1266 | export BUNDLER_EDITOR="$EDITOR" 1267 | else 1268 | export EDITOR="$(which vi)" 1269 | export BUNDLER_EDITOR="$EDITOR" 1270 | fi 1271 | ;; 1272 | *) # we're on a normal term console 1273 | if command -v mvim >/dev/null ; then 1274 | case "$TERM_PROGRAM" in 1275 | Apple_Terminal) _terminal="Terminal" ;; 1276 | iTerm.app) _terminal="iTerm" ;; 1277 | esac 1278 | export EDITOR="$(which mvim) -f -c \"au VimLeave * !open -a ${_terminal}\"" 1279 | export BUNDLER_EDITOR="$(which mvim)" 1280 | unset _terminal 1281 | elif command -v vim >/dev/null ; then 1282 | export EDITOR="$(which vim)" 1283 | export BUNDLER_EDITOR="$EDITOR" 1284 | elif command -v gvim >/dev/null ; then 1285 | export EDITOR="$(which gvim) -f" 1286 | export BUNDLER_EDITOR="$(which gvim)" 1287 | elif command -v mate >/dev/null ; then 1288 | export EDITOR="mate -w" 1289 | export EDITOR="mate" 1290 | else 1291 | export EDITOR="$(which vi)" 1292 | export BUNDLER_EDITOR="$EDITOR" 1293 | fi 1294 | ;; 1295 | esac 1296 | else # for remote/ssh sessions 1297 | if command -v vim >/dev/null ; then 1298 | export EDITOR="$(which vim)" 1299 | else 1300 | export EDITOR="$(which vi)" 1301 | fi 1302 | export BUNDLER_EDITOR="$EDITOR" 1303 | fi 1304 | export VISUAL="$EDITOR" 1305 | export GEM_EDITOR="$BUNDLER_EDITOR" 1306 | 1307 | # Set default visual tabstop to 2 characters, rather than 8 1308 | export EXINIT="set tabstop=2 bg=dark" 1309 | 1310 | # Number of commands to remember in the command history 1311 | export HISTSIZE=10000 1312 | 1313 | # The number of lines contained in the history file 1314 | export HISTFILESIZE=999999 1315 | 1316 | # Prepend a timestamp on each history event 1317 | export HISTTIMEFORMAT="%Y-%m-%dT%H:%M:%S " 1318 | 1319 | # Ignore commands starting with a space, duplicates, 1320 | # and a few others. 1321 | export HISTIGNORE="[ ]*:&:bg:fg:ls -l:ls -al:ls -la:ll:la" 1322 | 1323 | # Set the default command for fzf, if it's installed. Prefer `fd` for finding 1324 | # if present, and fall back to `rg` (ripgrep) if present (it's still crazy fast 1325 | # for finding files, even though that's not it's self-declared sweet spot) 1326 | if command -v fzf >/dev/null; then 1327 | if command -v fd >/dev/null; then 1328 | export FZF_DEFAULT_COMMAND="fd --type file --follow --hidden --exclude .git" 1329 | elif command -v rg >/dev/null; then 1330 | export FZF_DEFAULT_COMMAND="rg --files --no-ignore --hidden --follow -g '!.git/*'" 1331 | fi 1332 | fi 1333 | 1334 | export IGNOREEOF=10 1335 | 1336 | shopt -s checkwinsize 1337 | shopt -s histappend 1338 | 1339 | # Echo the version and date of the profile 1340 | __bashrc_version 1341 | 1342 | 1343 | #--------------------------------------------------------------- 1344 | # Completions 1345 | #--------------------------------------------------------------- 1346 | 1347 | complete -W "check init reload update version" bashrc 1348 | 1349 | # load in rvm completions, if rvm is loaded 1350 | safe_source "${rvm_path}/scripts/completion" 1351 | 1352 | safe_source_first /usr/local/git/contrib/completion/git-completion.bash \ 1353 | /usr/share/git/completion/git-completion.bash 1354 | 1355 | # load in some choice completions from homebrew if installed 1356 | if command -v brew >/dev/null ; then 1357 | if [ -f "$(brew --prefix)/etc/bash_completion" ] ; then 1358 | # bash-completion is installed 1359 | safe_source $(brew --prefix)/etc/bash_completion 1360 | else 1361 | safe_source "$(brew --prefix)/Library/Contributions/brew_bash_completion.sh" 1362 | safe_source $(brew --prefix)/etc/bash_completion.d/* 1363 | fi 1364 | fi 1365 | 1366 | case "$_os" in 1367 | Linux) 1368 | if [ -f "/etc/bash_completion" ] && ! shopt -oq posix; then 1369 | safe_source "/etc/bash_completion" 1370 | fi 1371 | ;; 1372 | FreeBSD) 1373 | safe_source "/usr/local/share/bash-completion/bash_completion" 1374 | ;; 1375 | esac 1376 | 1377 | if command -v rustup >/dev/null ; then 1378 | eval "$(rustup completions bash rustup)" 1379 | eval "$(rustup completions bash cargo)" 1380 | fi 1381 | 1382 | if command -v volta >/dev/null ; then 1383 | eval "$(volta completions bash)" 1384 | fi 1385 | 1386 | if command -v aws_completer >/dev/null ; then 1387 | complete -C "aws_completer" aws 1388 | fi 1389 | 1390 | if command -v gh >/dev/null ; then 1391 | eval "$(gh completion --shell bash)" 1392 | fi 1393 | 1394 | if command -v influx >/dev/null ; then 1395 | eval "$(influx completion bash)" 1396 | fi 1397 | 1398 | if command -v nsc >/dev/null ; then 1399 | eval "$(nsc completion bash)" 1400 | fi 1401 | 1402 | 1403 | #--------------------------------------------------------------- 1404 | # Post-environment initialization 1405 | #--------------------------------------------------------------- 1406 | 1407 | # load homeshick if installed 1408 | safe_source "$HOME/.homesick/repos/homeshick/homeshick.sh" 1409 | 1410 | if command -v zoxide >/dev/null ; then 1411 | eval "$(zoxide init bash)" 1412 | fi 1413 | 1414 | if command -v direnv >/dev/null ; then 1415 | # Ensure better compatibility between tmux & direnv, thanks to: 1416 | # https://github.com/direnv/direnv/issues/106#issuecomment-1027330218 1417 | if [[ -n "${TMUX:-}" && -n "${DIRENV_DIR:-}" ]]; then 1418 | # Unset vars starting with `DIRENV_` 1419 | unset "${!DIRENV_@}" 1420 | fi 1421 | eval "$(direnv hook "$SHELL")" 1422 | fi 1423 | 1424 | 1425 | #--------------------------------------------------------------- 1426 | # Set Aliases (Commonly Used Shortcuts) 1427 | #--------------------------------------------------------------- 1428 | 1429 | alias ll='ls -l' 1430 | alias la='ls -al' 1431 | alias lm='ll | less' 1432 | 1433 | alias bu='bashrc update' 1434 | 1435 | alias tf='tail -f' 1436 | 1437 | # Strip out ANSI color and escape characters on STDIN, thanks to: 1438 | # http://unix.stackexchange.com/questions/4527/program-that-passes-stdin-to-stdout-with-color-codes-stripped 1439 | alias strip-ansi="perl -pe 's/\e\[?.*?[\@-~]//g'" 1440 | 1441 | if command -v homesick >/dev/null ; then 1442 | __homesick_update() { 1443 | local castles="$(homesick list | awk '{print $2}' | \ 1444 | sed -e 's|^\([a-zA-Z0-9_ -]\{1,\}\).*$|\1|' | xargs)" 1445 | 1446 | for c in $castles ; do 1447 | printf -- "-----> Updating $c castle ...\n" 1448 | $(which homesick) pull "$c" --force 1449 | $(which homesick) symlink "$c" --force 1450 | done ; unset c 1451 | 1452 | printf -- "-----> homesick castles [$castles] are up to date.\n" 1453 | } 1454 | alias hsu=__homesick_update 1455 | fi 1456 | 1457 | if command -v vagrant >/dev/null ; then 1458 | alias vsh='vagrant ssh' 1459 | alias vst='vagrant status' 1460 | vup() { time (vagrant up $*) ; } 1461 | vpr() { time (vagrant provision $*) ; } 1462 | vre() { time (vagrant reload $*) ; } 1463 | alias vsu='vagrant suspend' 1464 | alias vde='vagrant destroy' 1465 | fi 1466 | 1467 | if command -v tmux >/dev/null; then 1468 | alias tn='tmux -u new -s "$(basename `pwd` | sed 's/\\\\./-/g')" || tmux -u attach -t "$(basename `pwd` | sed 's/\\\\./-/g')"' 1469 | alias ta='tmux -u attach' 1470 | alias tl='tmux ls' 1471 | fi 1472 | 1473 | alias be='bundle exec' 1474 | 1475 | # If pine is installed, eliminated the .pine-debugX files 1476 | [[ -s "/usr/local/bin/pine" ]] && alias pine="pine -d 0" 1477 | 1478 | # Skip the strict host checking and caching of known hosts for transient hosts 1479 | # and/or netbooted installer images, etc. 1480 | alias ssh-nocheck="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" 1481 | 1482 | # Use AWSP to easily switch between AWS Profiles 1483 | # See: https://github.com/johnnyopao/awsp 1484 | if command -v _awsp >/dev/null ; then 1485 | alias awsp="source _awsp" 1486 | fi 1487 | 1488 | # OS-specific aliases 1489 | case "$_os" in 1490 | Darwin) 1491 | # Add the super alias to properly become root with bash and 1492 | # environment settings 1493 | alias super="sudo -s -H" 1494 | 1495 | if [[ -z "$bashrc_light_bg" ]] ; then 1496 | # Default color scheme 1497 | export LSCOLORS="exfxcxdxbxegedabagacad" 1498 | fi 1499 | 1500 | # Colorize ls by default 1501 | alias ls="ls -G" 1502 | 1503 | # Colorize grep/egrep/fgrep by default 1504 | alias grep='grep --color=auto' 1505 | alias egrep='egrep --color=auto' 1506 | alias fgrep='fgrep --color=auto' 1507 | 1508 | # Lowercase uuids 1509 | alias uuidlower="uuidgen | tr '[[:upper:]]' '[[:lower:]]'" 1510 | 1511 | # List TCP port that are listening 1512 | # Thanks to: 1513 | # https://github.com/jqr/dotfiles/blob/master/bash_profile.d/mac.sh 1514 | alias openports='sudo lsof -iTCP -sTCP:LISTEN -P' 1515 | 1516 | # Update /etc/hosts 1517 | alias update_hosts='dscacheutil -flushcache' 1518 | 1519 | # Performs a fast logout (user switching) to lock your screen 1520 | alias lockscreen='/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend' 1521 | 1522 | # Puts the mac to sleep and exists shell session. Shell history gets preserved. 1523 | alias gotosleep='history -a && sudo shutdown -s now && exit' 1524 | 1525 | # set TMPDIR to /tmp for tmux commands. see: 1526 | # http://stackoverflow.com/questions/9039256/tmux-not-re-attaching 1527 | # also, force tmux to assume the terminal supports 256 colors 1528 | if [[ -n "$TMPDIR" ]] ; then 1529 | alias tmux='TMPDIR=/tmp tmux -2' 1530 | fi 1531 | 1532 | # Set the path to the X11 library (in Mountain Lion) for compiling 1533 | # 1.8.7 MRI. See: 1534 | # http://stackoverflow.com/questions/11664835/mountain-lion-rvm-install-1-8-7-x11-error#answer-11666019 1535 | if [[ -d "/opt/X11/include" ]] ; then 1536 | export CPPFLAGS="-I/opt/X11/include $CPPFLAGS" 1537 | fi 1538 | 1539 | if ! command -v tailscale >/dev/null; then 1540 | if [[ -x /Applications/Tailscale.app/Contents/MacOS/Tailscale ]]; then 1541 | alias tailscale='/Applications/Tailscale.app/Contents/MacOS/Tailscale' 1542 | fi 1543 | fi 1544 | 1545 | if [[ -d "/etc/profile.d" ]] && [[ -n "$(find /etc/profile.d -name '*.sh')" ]] ; then 1546 | safe_source $(ls -1 /etc/profile.d/*.sh | sort | xargs) 1547 | fi 1548 | ;; 1549 | SunOS) 1550 | # Colorize ls by default, courtesy of: 1551 | # http://blogs.sun.com/observatory/entry/ls_colors 1552 | if [ "$(command -v ls)" == "/usr/gnu/bin/ls" -a -x "/usr/bin/dircolors" ] ; then 1553 | eval "$(/usr/bin/dircolors -b)" 1554 | alias ls='ls --color=auto' 1555 | fi 1556 | 1557 | # Colorize grep/egrep/fgrep by default 1558 | if [ "$(command -v grep)" == "/usr/gnu/bin/grep" ] ; then 1559 | alias grep='grep --color=auto' 1560 | fi 1561 | if [ "$(command -v egrep)" == "/usr/gnu/bin/egrep" ] ; then 1562 | alias egrep='egrep --color=auto' 1563 | fi 1564 | if [ "$(command -v fgrep)" == "/usr/gnu/bin/fgrep" ] ; then 1565 | alias fgrep='fgrep --color=auto' 1566 | fi 1567 | ;; 1568 | Linux) 1569 | # Colorize ls by default 1570 | if command -v dircolors >/dev/null ; then 1571 | test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || \ 1572 | eval "$(dircolors -b)" 1573 | fi 1574 | alias ls='ls --color=auto' 1575 | 1576 | # Colorize grep/egrep/fgrep by default 1577 | alias grep='grep --color=auto' 1578 | alias egrep='egrep --color=auto' 1579 | alias fgrep='fgrep --color=auto' 1580 | 1581 | # Force tmux to assume the terminal supports 256 colors. 1582 | alias tmux='tmux -2' 1583 | 1584 | # Add macOS style `pbcopy` and `pbpaste` aliases using `xsel`, thanks to: 1585 | # https://gist.github.com/aarnone/83ce3b053ace037ada850d13133317f2 1586 | if command -v xsel >/dev/null ; then 1587 | alias pbcopy='xsel --clipboard --input' 1588 | alias pbpaste='xsel --clipboard --output' 1589 | fi 1590 | 1591 | # If the shell is interactive and not a login shell (i.e. the first 1592 | # character of argument zero is a `-`), then `/etc/profile` won't be 1593 | # sourced so we'll source any items under `/etc/profile.d` directly. 1594 | if [[ ! "$0" =~ ^- ]] && [[ -d "/etc/profile.d" ]] \ 1595 | && [[ -n "$(find /etc/profile.d -name '*.sh')" ]] ; then 1596 | safe_source $(ls -1 /etc/profile.d/*.sh | sort | xargs) 1597 | fi 1598 | ;; 1599 | FreeBSD) 1600 | # Colorize ls by default 1601 | alias ls="ls -G" 1602 | 1603 | # Colorize grep/egrep/fgrep by default 1604 | alias grep='grep --color=auto' 1605 | alias egrep='egrep --color=auto' 1606 | alias fgrep='fgrep --color=auto' 1607 | ;; 1608 | esac 1609 | 1610 | safe_source "${bashrc_prefix:-/etc/bash}/bashrc.local" "${HOME}/.bash_aliases" 1611 | 1612 | # Set shell prompt as late as possible to avoid other scripts (for example: 1613 | # `/etc/profile.d/*.sh`) to affect the final prompt 1614 | if command -v starship >/dev/null ; then 1615 | eval "$(starship init bash)" 1616 | unset bput short_pwd __prompt_state bash_prompt 1617 | else 1618 | bash_prompt 1619 | unset bash_prompt 1620 | fi 1621 | 1622 | cleanup 1623 | --------------------------------------------------------------------------------