429 lines
11 KiB
Bash
429 lines
11 KiB
Bash
#!/usr/bin/env bash # Best bashrc in history
|
|
#
|
|
# Author: Shane Peters <shane@shaner.life>
|
|
|
|
#
|
|
# 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 LANG=en_US.utf8
|
|
export HISTIGNORE="&:[ ]*:ls:ls -a:cd:cd .." # leave commands out of history log
|
|
export HISTCONTROL='ignoredups'
|
|
export HISTSIZE=5000
|
|
export HISTFILESIZE=5000
|
|
export PAGER='less'
|
|
export TZ='America/New_York'
|
|
export VISUAL=$EDITOR
|
|
export VAULT_TOKEN=root
|
|
export VAULT_ADDR=http://127.0.0.1:8200
|
|
[[ -x /usr/bin/lesspipe ]] && eval "$(SHELL=/bin/sh lesspipe)" # less more friendly for non-text
|
|
|
|
#
|
|
# 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
|
|
|
|
|
|
#
|
|
# 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
|
|
#
|
|
if [[ "$OSTYPE" == "darwin"* ]] || [[ "$OSTYPE" == "sun"* ]] ; then
|
|
# BSD/macOS
|
|
export LS_COLORS='ExGxbEaECxxEhEhBaDaCaD'
|
|
|
|
else
|
|
# Linux
|
|
export LS_COLORS='di=36:ln=35:su=31;47:sg=35;47'
|
|
fi
|
|
export GREP_COLOR='mt=1;36'
|
|
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 ls='ls --color=auto' # ls colored output
|
|
alias grep='grep --color=auto' # grep colored output
|
|
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
|
|
|
|
# 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
|
|
|
|
|
|
#
|
|
# 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"
|
|
}
|
|
|
|
|
|
# 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
|