Skip to content

Instantly share code, notes, and snippets.

@arthurl
Last active June 29, 2024 22:56
Show Gist options
  • Save arthurl/3bef7cd3bfd9c14e8a02ee1536a43bf1 to your computer and use it in GitHub Desktop.
Save arthurl/3bef7cd3bfd9c14e8a02ee1536a43bf1 to your computer and use it in GitHub Desktop.
# -*- mode: shell-script; -*-
# Enable colours in `ls` for Darwin
if [[ "${OS_NAME}" == Darwin ]]; then
export CLICOLOR=1
fi
# Use nano as editor
export EDITOR=nano
alias gs="git status -sb"
alias gl="git log --oneline --decorate --graph"
export FZF_DEFAULT_OPTS="--reverse -m --bind 'ctrl-r:toggle-sort'"
#------------------------------------------------------------------------------#
### Bash ###
# not attempt to search the PATH for possible completions when completion is
# attempted on an empty line
shopt -s no_empty_cmd_completion # bash>=2.04 only
# use "M-." to cycle through menu completions
bind '"\e.": menu-complete'
# use "M-," to cycle through menu completions backwards
bind '"\e,": menu-complete-backward'
#------------------------------------------------------------------------------#
### Bash history config ###
# save all lines of a multiple-line command in the same history entry. This
# allows easy re-editing of multi-line commands.
shopt -s cmdhist
# reedit a history substitution line if it failed
shopt -s histreedit
# edit a recalled history line before executing
shopt -s histverify
# Huge history. Doesn't appear to slow things down, so why not?
export HISTSIZE=999999999
export HISTFILESIZE=$HISTSIZE
# Avoid duplicate entries
export HISTCONTROL="ignorespace" #ignoreboth:ignorespace:erasedups
# see Emacs format-time-string function manual
export HISTTIMEFORMAT='%d %b %y %l:%M:%p » '
#------------------------------------------------------------------------------#
### Internal utilities ###
[[ "$(uname -s | grep -c CYGWIN)" -eq 1 ]] && OS_NAME="CYGWIN" || OS_NAME=$(uname -s)
## pclip -- Cross platform clipboard function
function pclip() {
if [[ "${OS_NAME}" == CYGWIN ]]; then
putclip "$@";
elif [[ "${OS_NAME}" == Darwin ]]; then
pbcopy "$@";
else
if command -v xsel >/dev/null 2>&1; then
xsel -ib "$@";
elif command -v xclip >/dev/null 2>&1; then
xclip -selection c "$@";
else
echo "Neither xsel or xclip is installed! Dumping to stdout:"
echo "$@"
fi
fi
}
#------------------------------------------------------------------------------#
### Bash history utilities ###
py_save_script="
from itertools import chain
import re
import sys
seperatorRe = re.compile(r'^#0#{78}$')
saveTokenRe = re.compile(r' #$')
timestampRe = re.compile(r'^#\d+$')
save = []
histIter = chain(sys.stdin, [None])
for line in histIter:
if line is not None and seperatorRe.match(line):
break
buffer = []
for line in histIter:
if line is None or timestampRe.match(line):
if len(buffer) > 1:
buffer[-1], nRep = saveTokenRe.subn('', buffer[-1], count=1)
if nRep != 0:
save.extend(buffer)
buffer = []
buffer.append(line)
for line in save:
print(line, end='')
"
function save_history() {
nix-shell -p python3 --run "python -c \"${py_save_script}\"" < ~/.bash_history >> ~/.bash_history.save
cp --reflink=always ~/.bash_history.save ~/.bash_history
echo '#0##############################################################################' >> ~/.bash_history
}
py_filter_script="
import re
import sys
import collections
reCmp = re.compile(r'^ ( *\d+ \d{2} [A-Z][a-z]{2} \d{2} [ \d]\d:\d{2}:[apAP][mM]) » (.*)$')
count = collections.OrderedDict()
prefix = {}
for line in sys.stdin:
m = reCmp.match(line)
if m:
cmd = m.group(2).strip()
if cmd in count:
count[cmd] += 1
else:
count[cmd] = 1
prefix[cmd] = m.group(1)
for cmd, n in count.items():
print('{:>4d}× '.format(n) + prefix[cmd] + ' » ' + cmd)
"
function h() {
save_history
# options to pass to fzf
local fzf_h_opts=("--no-hscroll" "--no-sort")
# history printout format is modified in my sensible bash config
local post_filter='s/^ *[0-9][0-9]*× *[0-9][0-9]* [0-9]\{2\} [A-Z][a-z]\{2\} [0-9]\{2\} [ 0-9][0-9]:[0-9]\{2\}:[apAP][mM] » \(.*\)$/\1/p'
# reverse history, pick up one line, remove new line characters and put it into clipboard
if [[ -z "$1" ]]; then
history | sed '1!G;h;$!d' | nix-shell -p python3 --run "python -c \"${py_filter_script}\"" | fzf "${fzf_h_opts[@]}" | sed -n "${post_filter}" | tr -d '\n' | pclip
else
history | rg "$1" | sed '1!G;h;$!d' | nix-shell -p python3 --run "python -c \"${py_filter_script}\"" | fzf "${fzf_h_opts[@]}" | sed -n "${post_filter}" | tr -d '\n' | pclip
fi
}
#------------------------------------------------------------------------------#
### Special file navigation utilities ###
# See: http://blog.binchen.org/posts/how-to-do-the-file-navigation-efficiently.html
function baseff() {
local fullpath="$*"
local filename="${fullpath##*/}" # remove "/" from the beginning
filename="${filename##*./}" # remove ".../" from the beginning
# Only the filename without path is needed
# filename should be reasonable
local cli
cli=$(find . \( -iwholename '*#' -o -iwholename '*/deployment/*' -o -iwholename '*/_doc/*' -o -iwholename '*/test/*' -o -iwholename '*/coverage/*' -o -iwholename '*/.gradle/*' -o -iwholename '*~' -o -iwholename '*.swp' -o -iwholename '*/dist/*' -o -iwholename '*.class' -o -iwholename '*.js.html' -o -iwholename '*.elc' -o -iwholename '*.pyc' -o -iwholename '*/bin/*' -o -iwholename '*/.config/*' -o -iwholename '*/vendor/*' -o -iwholename '*/bower_components/*' -o -iwholename '*/node_modules/*' -o -iwholename '*/.svn/*' -o -iwholename '*/.git/*' -o -iwholename '*/.gitback/*' -o -iwholename '*/.npm/*' -o -iwholename '*.sass-cache*' -o -iwholename '*/.hg/*' \) -prune -o -type f -iwholename '*'"${filename}"'*' -print | fzf)
# convert relative path to full path
echo "$(cd "$(dirname "$cli")" || exit; pwd)"/"$(basename "$cli")"
}
function ff() {
local cli
cli="$(baseff "$*")"
echo "${cli}"
echo -n "${cli}" | pclip
}
#------------------------------------------------------------------------------#
### My custom functions ###
## pgen -- Generates passwords
#
# 1st arg: optional. Length of password. Default 32.
#
# 2nd arg: optional. Specifies characters to include. By default includes all
# printable ASCII characters except spaces. See `man tr` for list of valid
# character ranges.
function pgen() {
local passwd_len="${1:-32}"
local new_passwd
if [[ -z "${2}" ]]; then
# Password character range not specified
new_passwd=$(LC_ALL=C < /dev/urandom tr -cd "[:print:]" | tr -d ' ' | head -c "${passwd_len}")
else
# Password character range specified
new_passwd=$(LC_ALL=C < /dev/urandom tr -cd "[:print:]" | tr -d ' ' | tr -cd "${2}" | head -c "${passwd_len}")
fi
printf '%s' "${new_passwd}" | pclip && echo "${new_passwd}"
}
## mkcmd_b64reconstruct -- Constructs a shell command that reconstructs a file.
## Useful for pasting into a serial terminal.
#
# 1st arg: Filename.
function mkcmd_b64reconstruct () {
if [[ -f "${1}" ]]; then
local b64data
b64data=$(gzip < "${1}" | base64)
filename=$(basename "${1}")
echo "echo \"${b64data}\" | base64 --decode | gzip --decompress > ${filename}" | pclip
else
echo "ERROR: No file specified."
fi
}
# -*- mode: shell-script; -*-
#------------------------------------------------------------------------------#
### My custom functions ###
function sshu() {
local remote="${1:-arthur@luyten.arthur.li}"
local error_cmd="display notification 'Connection error!' with title \"sshuttle ${remote}\""
# Note: the bracket below are only for clarity, and are not required (i.e.
# semantically identical without).
(sudo true && sshuttle --dns -r "${remote}" 0/0) || osascript -e "${error_cmd}"
}
## rename_import_email -- Rename .eml files.
#
# args: Filenames.
function rename_import_email() {
local - # paranoia; in case the python activate script sets shell options
(
source "/home/arthur/.cache/pypoetry/virtualenvs/arthurlib-oQ_WqyeL-py3.10/bin/activate" # requires python-dateutil package
python "/home/arthur/Git/bashrc_portable/email_import.py" "${@}"
)
}
## ipynb2pdf -- Prints ipython notebooks as PDFs
#
# args: Filenames.
function ipynb2pdf() {
local - # paranoia; in case the python activate script sets shell options
(
source "/home/arthur/.cache/pypoetry/virtualenvs/arthurlib-oQ_WqyeL-py3.10/bin/activate" # requires python-dateutil package
python "/home/arthur/Git/bashrc_portable/ipynb2pdf.py" "${@}"
)
}
## monitor_vpn -- Pings 2 targets, one through VPN and one without
#
# arg 1: Approx interval in integeral seconds.
# arg 2: Number of pings.
# arg 3: Host with VPN.
# arg 4: Host without VPN.
function monitor_vpn() {
local interval="${1:-3}"
local target_vpn="${3:-se1.socks.azirevpn.net}"
local target_local="${4:-192.168.1.254}"
for i in $(seq -w 1 "${2:-9999}"); do
date "+${i} %H:%M:%S"
local left_pad=' '
# run in subshell to remove monitor messages
( (x=$(ping -t "${interval}" -c1 "${target_vpn}" | sed '2q;d'); echo "${left_pad}+: ${x:-${target_vpn} FAILED}") & )
( (x=$(ping -t "${interval}" -c1 "${target_local}" | sed '2q;d'); echo "${left_pad}-: ${x:-${target_local} FAILED}") & )
sleep "${interval}.1"
done
}
#------------------------------------------------------------------------------#
### ReMarkable ###
## md2rm -- Compile markdown to PDF.
#
# args: Filenames.
function md2rm() {
for ff in "${@}"; do
pandoc -s -f markdown+tex_math_single_backslash+smart --template ~/Git/tex-template/template.tex -o "$ff.pdf" "$ff"
done
}
## send2rm -- Send file to ReMarkable tablet.
#
# args: Filenames.
function send2rm() {
for ff in "${@}"; do
local fullpath
fullpath=$(realpath "${ff}")
local filename
filename=$(basename "${ff}")
echo "Uploading: ${fullpath}"
curl 'http://10.11.99.1/upload' -H 'Origin: http://10.11.99.1' -H 'Accept: */*' -H 'Referer: http://10.11.99.1/' -H 'Connection: keep-alive' -F "file=@${fullpath};filename=${filename};type=application/pdf"
echo ""
done
}
from sys import argv
from email.parser import BytesHeaderParser
from dateutil import parser
from datetime import datetime, timedelta
from os import utime
from pathlib import Path
from hashlib import md5
if __name__ == '__main__':
for filename in argv[1:]:
try:
with open(filename, mode='rb') as fp:
bMsg = fp.read()
msgDateStr = BytesHeaderParser().parsebytes(bMsg)['Date']
msgHash = md5(bMsg).hexdigest()
except FileNotFoundError:
print('File', filename, 'not found!')
else:
if msgDateStr:
# Set mtime to 'Date' header
msgSentTime = parser.parse(msgDateStr).timestamp()
utime(filename, (msgSentTime, msgSentTime))
# Rename email file to a standard name
currentTimestamp = int((datetime.utcnow() - datetime(1970, 1, 1)) / timedelta(microseconds=1))
(tSeconds, tMilliseconds) = divmod(currentTimestamp, 1000000)
p = Path(filename).resolve() # just in case file is not in current directory
p.rename(p.parent / '{:d}.{:06d}.import_{:s}'.format(tSeconds, tMilliseconds, msgHash))
else:
print('Cannot find sent date in', filename)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment