Files
dotfiles/bashrc
2024-11-05 10:18:47 -05:00

431 lines
12 KiB
Bash

#!/usr/bin/env bash
# Best bashrc in history
#
# Author: Shane Peters <shane@shaner.life>
# SSH agent
SSH_ENV="$HOME/.ssh/agent-environment"
start_agent() {
/usr/bin/ssh-agent | sed 's/^echo/#echo/' >"$SSH_ENV"
chmod 600 "$SSH_ENV"
. {$SSH_ENV} >/dev/null
/usr/bin/ssh-add;
}
if [ -f "${SSH_ENV}" ]; then
. ${SSH_ENV} >/dev/null
ps -ef | grep $SSH_AGENT_PID | grep ssh-agent$ >/dev/null || {
start_agent
}
else
start_agent
fi
# Set environment
# Support colors in less
export LESS_TERMCAP_mb=$(tput bold; tput setaf 1)
export LESS_TERMCAP_md=$(tput bold; tput setaf 1)
export LESS_TERMCAP_me=$(tput sgr0)
export LESS_TERMCAP_se=$(tput sgr0)
export LESS_TERMCAP_so=$(tput bold; tput setaf 3; tput setab 4)
export LESS_TERMCAP_ue=$(tput sgr0)
export LESS_TERMCAP_us=$(tput smul; tput bold; tput setaf 2)
export LESS_TERMCAP_mr=$(tput rev)
export LESS_TERMCAP_mh=$(tput dim)
export LESS_TERMCAP_ZN=$(tput ssubm)
export LESS_TERMCAP_ZV=$(tput rsubm)
export LESS_TERMCAP_ZO=$(tput ssupm)
export LESS_TERMCAP_ZW=$(tput rsupm)
#
# Alternate Paths
#
[[ -d ~/Bin ]] && export PATH=~/Bin:$PATH # local binaries & scripts
[[ -d ~/Bin/streams ]] && export PATH=~/Bin/streams:$PATH # radio streams
[[ -d /usr/local/cuda/bin ]] && export PATH=/usr/local/cuda-11.8/bin:$PATH
[[ -d /opt/node/node/bin ]] && export PATH=/opt/node/node/bin:$PATH # local binaries & scripts
[[ -d /opt/zeek/bin ]] && export PATH=/opt/zeek/bin:$PATH
[[ -d ~/.local/bin ]] && export PATH=~/bin:~/.local/bin:$PATH
[[ -d ~/.cargo/bin ]] && export PATH=~/.cargo/bin:$PATH
#
# App env variables
#
export EDITOR='vim'
export GREP_COLOR='1;36'
export HISTIGNORE="&:[ ]*:ls:ls -a:cd:cd .." # leave commands out of history log
export HISTCONTROL='ignoredups'
export HISTSIZE=5000
export HISTFILESIZE=5000
export LSCOLORS='ExGxbEaECxxEhEhBaDaCaD'
export PAGER='less'
export TZ='America/New_York'
export VAULT_TOKEN=root
export VAULT_ADDR=http://127.0.0.1:8200
export LANG=en_US.utf8
export VISUAL=$EDITOR
[[ -x /usr/bin/lesspipe ]] && eval "$(SHELL=/bin/sh lesspipe)" # less more friendly for non-text
#
# bash options
#
shopt -s cdspell
shopt -s extglob
shopt -s checkwinsize # updates values of LINES and COLUMNS
shopt -s nocaseglob # case-insensitive pathname expansion
shopt -s autocd # enter directory without cd
shopt -s cdspell # correct minor errors in directory names with cd
shopt -s dirspell # attempt spelling correction on directory names in completion
shopt -s dotglob # includes filenames beginning with a `.' in filename expansion
shopt -s histappend # append to history file, instead of overwriting it
shopt -s no_empty_cmd_completion # not attempt to search for possible completions on an empty line.
shopt -s globstar # recursive globbing with **
shopt -s expand_aliases # expand aliases
shopt -s cmdhist # save all lines of a multiline command in same entry
shopt -s lithist # save all lines of a multiline command in same entry
stty -ixon # disable ^S/^Q flow control
#
# colors
#
#alias ls='ls --color=auto' # ls colored output
export GREP_COLOR="mt=1;36" # grep colored ouput
alias grep='grep --color=auto' # grep colored ouput
export LESS="-R" # less colored output
export LESS_TERMCAP_mb=$'\E[01;31m' # begin blinking
export LESS_TERMCAP_md=$'\E[01;38;5;74m' # begin bold
export LESS_TERMCAP_me=$'\E[0m' # end mode
export LESS_TERMCAP_se=$'\E[0m' # end standout-mode
export LESS_TERMCAP_so=$'\E[38;5;246m' # begin standout-mode - info box
export LESS_TERMCAP_ue=$'\E[0m' # end underline
export LESS_TERMCAP_us=$'\E[04;38;5;146m' # begin underline
# Aliases
alias ..='echo "cd .."; cd ..'
alias ag='rg' # sorry silver searcher
alias chomd='chmod'
alias curl='curl -A "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"'
alias externalip='curl -sS https://www.daveeddy.com/ip'
alias gerp='grep'
alias hl='rg --passthru'
alias l='ls'
alias ll='ls -lrtha'
alias suod='sudo'
alias gl='git log -p'
alias wget='wget --user-agent="Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0"'
alias vrd='VAULT_UI=true VAULT_REDIRECT_ADDR=http://127.0.0.1:8200 vault server -log-level=trace -dev -dev-root-token-id=root'
# Git Aliases
alias nb='git checkout -b "$USER-$(date +%s)"' # new branch
alias ga='git add . --all'
alias gb='git branch'
alias gc='git clone'
alias gci='git commit -a'
alias gco='git checkout'
alias gd="git diff ':!*lock'"
alias gdf='git diff' # git diff (full)
alias gi='git init'
alias gl='git log'
alias gp='git push origin HEAD'
alias gr='git rev-parse --show-toplevel' # git root
alias gs='git status'
alias gt='git tag'
alias gu='git pull' # gu = git update
# Functions
sscreate() {
openssl req \
-x509 \
-nodes \
-newkey rsa:4096 \
-keyout $1_key.pem \
-out $1_cert.pem \
-days 365 \
-subj "/C=US/ST=Ohio/L=Columbus/O=ColumOps/OU=OPS/CN=$1"
}
compress() {
FILE=$1
case $FILE in
*.tar.bz2) shift && tar cjf $FILE $* ;;
*.tar.gz) shift && tar czf $FILE $* ;;
*.tgz) shift && tar czf $FILE $* ;;
*.zip) shift && zip $FILE $* ;;
*.rar) shift && rar $FILE $* ;;
*.7z) shift && 7za a $FILE $* ;;
esac
}
extract() {
local e=0 i c
for i; do
if [ -f $i && -r $i ]; then
c=
case $i in
*.tar.bz2) c='tar xjf' ;;
*.tar.gz) c='tar xzf' ;;
*.bz2) c='bunzip2' ;;
*.gz) c='gunzip' ;;
*.tar) c='tar xf' ;;
*.tbz2) c='tar xjf' ;;
*.tgz) c='tar xzf' ;;
*.7z) c='7z x' ;;
*.Z) c='uncompress' ;;
*.exe) c='cabextract' ;;
*.rar) c='unrar x' ;;
*.xz) c='unxz' ;;
*.zip) c='unzip' ;;
*) echo "$0: cannot extract \`$i': Unrecognized file extension" >&2; e=1 ;;
esac
[ $c ] && command $c "$i"
else
echo "$0: cannot extract \`$i': File is unreadable" >&2; e=2
fi
done
return $e
}
mkiso() {
mkisofs -V $2 -J -r $1 -o isoimage.iso
}
# because `master` is sometimes `main` (or others), these must be functions.
gmb() { # git main branch
local main
main=$(git symbolic-ref --short refs/remotes/origin/HEAD)
main=${main#origin/}
[[ -n $main ]] || return 1
echo "$main"
}
# show the diff from inside a branch to the main branch
gbd() { # git branch diff
local mb=$(gmb) || return 1
git diff "$mb..HEAD"
}
# checkout the main branch and update it
gcm() { # git checkout $main
local mb=$(gmb) || return 1
git checkout "$mb" && git pull
}
# merge the main branch into our branch
gmm() { # git merge $main
local mb=$(gmb) || return 1
git merge "$mb"
}
# Prompt
# Store `tput` colors for future use to reduce fork+exec
# the array will be 0-255 for colors, 256 will be sgr0
# and 257 will be bold
COLOR256=()
COLOR256[0]=$(tput setaf 1)
COLOR256[256]=$(tput sgr0)
COLOR256[257]=$(tput bold)
# Colors for use in PS1 that may or may not change when
# set_prompt_colors is run
PROMPT_COLORS=()
# Change the prompt colors to a theme, themes are 0-29
set_prompt_colors() {
local h=${1:-0}
local color=
local i=0
local j=0
for i in {22..231}; do
((i % 30 == h)) || continue
color=${COLOR256[$i]}
# cache the tput colors
if [[ -z $color ]]; then
COLOR256[$i]=$(tput setaf "$i")
color=${COLOR256[$i]}
fi
PROMPT_COLORS[$j]=$color
((j++))
done
}
# Construct the prompt
# [(exit code)] <user> - <hostname> <uname> <cwd> [git branch] <$|#>
# exit code of last process
PS1='$(ret=$?;(($ret!=0)) && echo "\[${COLOR256[0]}\]($ret) \[${COLOR256[256]}\]")'
# username (red for root)
PS1+='\[${PROMPT_COLORS[0]}\]\[${COLOR256[257]}\]$(((UID==0)) && echo "\[${COLOR256[0]}\]")\u\[${COLOR256[256]}\]@'
# hostname
PS1+='\[${PROMPT_COLORS[3]}\]\h '
# zonename (global zone warning)
# PS1+='\[${COLOR256[0]}\]\[${COLOR256[257]}\]'"$(zonename 2>/dev/null | grep -q '^global$' && echo 'GZ:')"'\[${COLOR256[256]}\]'
# uname
#PS1+='\[${PROMPT_COLORS[2]}\]'"$(uname | tr '[:upper:]' '[:lower:]')"' '
# cwd
PS1+='\[${PROMPT_COLORS[5]}\]\w '
# optional git branch
PS1+='$(branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null); [[ -n $branch ]] && echo "\[${PROMPT_COLORS[2]}\](\[${PROMPT_COLORS[3]}\]git:$branch\[${PROMPT_COLORS[2]}\]) ")'
# prompt character
PS1+='\[${PROMPT_COLORS[0]}\]\$\[${COLOR256[256]}\] '
# set the theme
set_prompt_colors 24
# Prompt command
_prompt_command() {
local user=$USER
local host=${HOSTNAME%%.*}
local pwd=${PWD/#$HOME/\~}
local ssh=
[[ -n $SSH_CLIENT ]] && ssh='[ssh] '
printf "\033]0;%s%s@%s:%s\007" "$ssh" "$user" "$host" "$pwd"
}
PROMPT_COMMAND=_prompt_command
PROMPT_DIRTRIM=6
# Print all 256 colors
colors() {
local i
for i in {0..255}; do
printf "\x1b[38;5;${i}mcolor %d\n" "$i"
done
tput sgr0
}
# Copy stdin to the clipboard
copy() {
pbcopy 2>/dev/null ||
xsel 2>/dev/null ||
clip.exe
}
# Convert epoch to human readable (print current date if no args)
epoch() {
local num=${1:--1}
printf '%(%B %d, %Y %-I:%M:%S %p %Z)T\n' "$num"
}
# Open the current path or file in GitHub
gho() {
local file=$1
local remote=${2:-origin}
# get the git root dir, branch, and remote URL
local gr=$(git rev-parse --show-toplevel)
local branch=$(git rev-parse --abbrev-ref HEAD)
local url=$(git config --get "remote.$remote.url")
[[ -n $gr && -n $branch && -n $remote ]] || return 1
# construct the path
local path=${PWD/#$gr/}
[[ -n $file ]] && path+=/$file
# extract the username and repo name
local a
IFS=:/ read -a a <<< "$url"
local len=${#a[@]}
local user=${a[len-2]}
local repo=${a[len-1]%.git}
url="https://github.com/$user/$repo/tree/$branch$path"
echo "$url"
open "$url"
}
# Platform-independent interfaces
interfaces() {
node <<-EOF
var os = require('os');
var i = os.networkInterfaces();
Object.keys(i).forEach(function(name) {
i[name].forEach(function(int) {
if (int.family === 'IPv4') {
console.log('%s: %s', name, int.address);
}
});
});
EOF
}
# Calculate CPU load / Core Count
load() {
node -p <<-EOF
var os = require('os');
var c = os.cpus().length;
os.loadavg().map(function(l) {
return (l/c).toFixed(2);
}).join(' ');
EOF
}
# Platform-independent memory usage
meminfo() {
node <<-EOF
var os = require('os');
var free = os.freemem();
var total = os.totalmem();
var used = total - free;
console.log('memory: %dmb / %dmb (%d%%)',
Math.round(used / 1024 / 1024),
Math.round(total / 1024 / 1024),
Math.round(used * 100 / total));
EOF
}
# print lines over X columns (defaults to 80)
over() {
awk -v c="${1:-80}" 'length($0) > c {
printf("%4d %s\n", NR, $0);
}'
}
# print a rainbow if truecolor is available to the terminal
truecolor-rainbow() {
local i r g b
for ((i = 0; i < 77; i++)); do
r=$((255 - (i * 255 / 76)))
g=$((i * 510 / 76))
b=$((i * 255 / 76))
((g > 255)) && g=$((510 - g))
printf '\033[48;2;%d;%d;%dm ' "$r" "$g" "$b"
done
tput sgr0
echo
}
# Follow redirects to untiny a tiny url
untiny() {
local location=$1
local last_location=''
while [[ -n $location ]]; do
[[ -n $last_location ]] && echo " -> $last_location"
last_location=$location
read -r _ location < \
<(curl -sI "$location" | grep 'Location: ' | tr -d '[:cntrl:]')
done
echo "$last_location"
}
# load completions
source /usr/share/bash-completion/completions/fzf
source /usr/share/doc/fzf/examples/key-bindings.bash
source /etc/bash/bash_completion 2>/dev/null
# done
true