look ma, i'm putting my personal preferences up on the internet for all to see!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connor Olding cb705df268 use cursed code style 6 days ago
home use cursed code style 6 days ago
mpv add basic mpv config 1 year ago
sh don't autoload `witch` in bash 6 days ago
ssh remove known_hosts 'cause it got annoying 7 years ago
vim kill vim9 comments with an `after/` instead of an autogroup 12 months ago
.gitignore remove ancient db alias and known_hosts exclusion 6 months ago
README.md regenerate readme 6 days ago
install rename `~/.-shrc` to `~/.shrc` 11 months ago
regenerate rename `~/.-shrc` to `~/.shrc` 11 months ago
tableize add handling for perl to compatibility table 11 months ago


obligatory personal dotfiles repository

(plus some little shell scripts)

quick install for random boxes:

# with curl:
cd && curl -L https://github.com/notwa/rc/archive/master.tar.gz | tar zx && mv rc-master rc && rc/install
# with wget:
cd && wget -O - https://github.com/notwa/rc/archive/master.tar.gz | tar zx && mv rc-master rc && rc/install

the following shells are taken into consideration, ordered from most to least compatible:

  • zsh
  • bash
  • dash
  • ash (busybox)

refer to the compatibility table for specifics.

NOTE: everything below this line is overwritten and automatically regenerated.

shell functions


create an archive file in one of a few formats.

borrowed from prezto.


validate the number of arguments in a function.

# usage: myfunc() { argc $# -(eq|le|ge) [0-9] "$0" || return; }

myfunc() {
    # use one of the following:
    argc $# -eq N "$0" || return
    argc $# -le N "$0" || return
    argc $# -ge N "$0" || return
    # where N is an integer between 0 and 9.


perform arithmetic using the shell and display the result. see also hex and bin. this example requires zsh:

% db=6
% noglob arith 10**(db/20.)


download, edit, make, and install packages from the AUR. it's a little broken.

$ aur -eyoI cmdpack-uips applyppf


combine inotifywait and rsync. this is sometimes nicer than ssh-ing into a server and running vim remotely.


backup files by creating copies and appending ".bak" to their names. this calls itself recursively to avoid clobbering existing backups.

$ touch -d '2001-12-25 16:30:00' butts
$ bak butts
$ touch butts
$ bak butts
$ ls -l
total 0
-rw-r--r-- 1 notwa None 0 Aug  1 08:02 butts
-rw-r--r-- 1 notwa None 0 Aug  1 08:02 butts.bak
-rw-r--r-- 1 notwa None 0 Dec 25  2001 butts.bak.bak


backup files by appending their timestamps given by now.

$ touch -d '2001-12-25 16:30:00' butts
$ baknow butts
$ baknow butts
cp: overwrite 'butts.2001-12-26_01800000.bak'? n
$ ls -l
total 0
-rw-r--r-- 1 notwa None 0 Dec 25  2001 butts
-rw-r--r-- 1 notwa None 0 Dec 25  2001 butts.2001-12-26_01800000.bak


backup files by copying each and appending the current date-time, irrespective of when the files were modified or created.

$ touch -d '2001-12-25 16:30:00' butts
$ baks butts
$ baks butts
$ ls -l
total 0
-rw-r--r-- 1 notwa None 0 Dec 25  2001 butts
-rw-r--r-- 1 notwa None 0 Dec 25  2001 butts.21-08-01_14-54-07.bak
-rw-r--r-- 1 notwa None 0 Dec 25  2001 butts.21-08-01_14-54-09.bak


perform arithmetic using the shell and display the result as an unsigned 8-bit integer in binary. see also arith and hex.

$ bin 123


list directories in descending order by the number of files in them, counted recursively.

$ cd && busiest | head -n3
144181 src
48840 work
21042 play


display all combinations of foreground and background terminal colors. this only includes the basic 16-color palette. excluding boilerplate, this script is a mere 76 characters long!

terminal colors

setup_clang_ubuntu (sh/compile)

print (but don't execute) the commands necessary to install a fairly recent version of clang on ubuntu-based distros.

$ setup_clang_ubuntu bionic
wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
echo -n "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
# deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
# 12
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main
# deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main
" > /etc/apt/sources.list.d/llvm-toolchain-bionic.list
apt-get update
apt-get install clang-12
apt-get install lld-12
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-12 1200
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-12 1200
update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /usr/bin/llvm-symbolizer-12 1200


compile single-file C and C++ programs, messily.

supports gcc and clang on *nix, and mingw64 gcc, msvc clang, and regular msvc on Windows. tested on x86_64 and on ARMv7 as well. does not support MacOS, maybe someday…

defaults to gnu11 and gnu++1z as C and C++ standards respectively. defaults to clang, gcc, and msvc in that order.

compile attempts to guess the most sane switches for any program, so that compilation may reduce to:

# debug build
compile rd.c
compile debug rd.c
# debug build with warning/error flags defined in ~/sh/arrays
# (requires .zshrc for global alias expansion)
compile WHOA rd.c
# likewise for C++
compile WHOA WELP rd.cc
compile WHOA WELP rd.cpp
# "derelease" build (release build with debug information)
compile derelease WHOA rd.c
# release build (with symbols stripped)
compile release WHOA rd.c
# hardened build (only useful on *nix)
compile hardened WHOA rd.c
# specifying compiler
compile gcc WHOA rd.c
compile msvc WHOA rd.c
compile release clang WHOA rd.c
# compile and execute (FIXME: writing to /tmp is a security concern)
compile derelease rd.c && /tmp/rd


display a simple yes-or-no prompt and return 0-or-1 respectively.

$ confirm && echo yay || echo nay
Continue? [y/N] y
$ confirm && echo yay || echo nay
Continue? [y/N] n

a real world example:

$ g1 && confirm && git commit -a --amend --no-edit
daf84e3 document a ton of stuff
Continue? [y/N] y
[master 92bdf76] document a ton of stuff
 Date: Sun Aug 1 09:27:25 2021 -0700
 20 files changed, 406 insertions(+), 29 deletions(-)


count the number of lines changed between two files.

TODO: don't use git for this. also, use patience algorithm.

$ countdiff README-old.md README.md


(WIP) create a short clip of a long video file.


compute the number of days since a given date.

$ days 'January 1 1970'


given a list of directories, update the last-modified timestamp of each argument to that of the most recent file that it contains.

note that files are found recursively, but only the outermost directory (the one specified by argument) has its timestamp updated. symlinks are followed. .git subdirectories are skipped over. the timestamps of subdirectories are ignored.


pretty-print df in GiB.

$ dfu
Filesystem              Used     Max    Left    Misc
/dev                    0.00    0.46    0.46    0.00
/                      17.20   23.22    6.01    1.27


find files in system directories that aren't associated with any pacman packages.


generate a markdown file out of docstrings in shell scripts.

TODO: describe. i have a rough outline written in my scrap file.


wrap around $EDITOR to run it as root if necessary. this still needs some work to detect root-owned directories.

$ e /etc/sudoers
[sudo] password for notwa: 

NOTE: there also exists an e(1) program provided by the e-wrapper package that i don't use.


TODO: document.


print arguments joined by spaces to stderr without parsing anything.

$ echo -e 'this\nthat' those
that those
$ echo2 -e 'this\nthat' those
-e this\nthat those


open a single directory in explorer.exe, defaulting to $PWD.


select a file from a given or current directory using fzy.


convert a markdown file to HTML in the style of GitHub. note that this uses GitHub's API, so it requires internet connectivity.

this script utilizes the CSS provided at sindresorhus/github-markdown-css.

~/sh/ghmd < ~/rc/README.md > ~/rc/README.html


invoke grep with -oP.

NOTE: there also exists a grop(1) program provided by the grop package that i don't use.


grop for IPv4s.


have, silently.


print the result of which if the program is found, else simply return 1.

export SOLVER="$(have kissat || have picosat || have cadical || have minisat)"


perform arithmetic using the shell and display the result as an unsigned 32-bit integer in hexadecimal. see also arith and bin.

$ hex 0x221EA8-0x212020

NOTE: there also exists a hex(1) program provided by the basez package that i don't use.


pipe one command through another, so you can still pass arguments to the former.

this is mainly useful for aliases. 99% of the time you'll use this with less.

$ alias ll="ify less ls -ACX --group-directories-first --color=force"
$ ll /etc


return 0 if the directory given by argument is empty.


return 0 if a given website returns a 2xx HTTP code.

$ isup google.com && echo yay || echo nay
$ isup fdhafdslkjgfjs.com && echo yay || echo nay


join every other line.


list the contents of an archive file in one of many formats.

borrowed from prezto.

maybesudo_ (sh/maybesudo)

mimic certain features of sudo for systems without it installed. as it stands, this mostly just handles some environment variables.

try this: maybesudo_ -u "$USER" printenv


check if the current minute is divisible by a given number, and optionally execute a command if it is. if a command is given, either execute the command and return its exit value, or execute nothing and return 0. if a command is omitted, either return 0 on the minute, or return 1.

note that a "minute" is relative to the seconds since the epoch, not the minute of the hour. this ensures that commands will run roughly every N minutes, regardless of the minute hand on the clock.

note that minutemaid 1 will always return 0, and minutemaid 1 command will always execute the command, since every integral interval is evenly divisible by 1. minutemaid 0, and any negative interval, is an error.

# crontab usage:
* * * * * minutemaid 9 ~/work/do_my_bidding # runs every nine minutes
# loop usage:
until minutemaid 9; do sleep 5; done
echo the wait is finally over; date
# improper usage:
while minutemaid 1; do sleep 1; done
echo this will never happen


this is watch(1) loosely reimplemented as a shell script.

usage: monitor [-fs] [-n {period}] {command} [{args...}]

NOTE: there also exists monitor(1) programs provided by the 389-ds-base and dmucs packages that i don't use.


print all 256 colors that are available on most terminals.


strip C-like comments; both multi-line and single-line.


act like echo2, but use a bright color to stand out more.

NOTE: there also exists a note(1) program provided by the note package that i don't use.


print a date-time (UTC) in a sortable format. this takes a date or file as an argument, else it defaults to the current time.

$ now
$ now ~/sh/monitor
$ now '@1234567890'


upload files (or stdin) to 0x0.st. this script exits with the number of failed uploads; up to 255 at once. file retention period (30 to 365 days) is only computed for arguments. directories are skipped. please review the terms of service on the website before uploading files.

$ echo test | oxo
oxo: successfully uploaded 1/1 file
$ oxo ~/play/{hey,you,fake,empty}
oxo: expires in 365 days: /home/notwa/play/hey
oxo: expires in 365 days: /home/notwa/play/you
oxo: no such file: /home/notwa/play/fake
oxo: skipping empty file: /home/notwa/play/empty
oxo: successfully uploaded 2/4 files
oxo: failed to upload 2/4 files


display and order installed pacman packages by their filesize ascending, and their sum. requires expac.

$ pacbm | head -n -1 | tail -2
  204.78M clang
  235.44M linux-firmware


pause — the companion script of confirm.

$ pause
Press any key to continue


download and (pip) install a Python "egg" from a project on GitHub, defaulting to the master branch. this uses pippy internally.

# install the development version of https://github.com/rthalley/dnspython
$ pegg rthalley dnspython
# or instead install the latest stable version (as of writing)
$ pegg rthalley dnspython 3933b49


install Python packages using pip, but only update their dependencies as required. this uses maybesudo internally.


dump all the #defines that $CC $CPPFLAGS $CFLAGS $LDFLAGS would result in.

$ pre | shuf | head -n10
#define __GNUC_MINOR__ 3
#define __SIZEOF_LONG__ 4
#define __UINT_LEAST16_TYPE__ short unsigned int
#define __ORDER_BIG_ENDIAN__ 4321
#define __SIZEOF_FLOAT__ 4
#define __INTMAX_MAX__ 0x7fffffffffffffffLL
#define __INT64_C(c) c ## LL
#define __UINT16_MAX__ 0xffff
#define __DEC64_MANT_DIG__ 16
#define __DBL_HAS_INFINITY__ 1


handle dependencies within the ~/sh/ directory.

this function contains more comments than code, so you should read it.


display and order processes by their memory usage ascending, and their sum.

$ psbm | head -n -1 | tail -2
  185.08M    1163 chromium
  199.95M    1060 chromium


display a random directory in the current working directory.

$ randir


invoke hash -r.


rot13 with numbers rotated as well.

$ rot13 <<< abc123

NOTE: there also exists rot13(1) programs provided by the bsdgames and hxtools packages that i don't use.


record screen. does not record audio. currently only works on Windows (gdigrab). i'm sure there's something equivalent for Linux.

TODO: consider renaming because rs(1) already exists.




upload given files to a webserver and return a direct link for sharing them. you'll want to tweak this if you use it yourself. this contains some extra logic for screenshots created by scropt.

TODO: consider renaming because sc(1) already exists.


perform sort | uniq -c | sort -n, preferring GNU awk when available.


scrambles text in a predictable way using regex.

sacbremls ttex in a pdrceailtbe way unsig reegx.

TODO: consider renaming because scramble(1) already exists.


run scrot through optipng and save the result to ~/play/$(now).png.

$ ~/sh/sc $(~/sh/scropt -s -d0.5)


comment out text from stdin and wrap it in a markdown blockquote for docstrings. this contains some extra logic for handling already-commented and already-quoted text. this allows shcom to be used with vim's visual selections to update existing code examples.

as a simple example, echo hey | shcom produces, verbatim:



(perl 5) invoke the first shell found from a list of shells as an interactive, non-login shell. arguments are ignored.


highlight adjacent lines up to the first inequivalent character.


view specific columns of text.


view specific columns of text. this version of slit uses tabs for its field separators.


sort lines numerically by IPv4 segments.


convert between a couple saveram formats for N64 emulators.


invoke a command, silencing stdout and stderr unless the command fails.

NOTE: don't use stfu for handling sensitive data or commands! use it for 7zip.

note that the tail commands in the example below are from stfu itself; they are echoed to reveal the temp paths for any further investigation.

$ touch butts
$ stfu 7z a butts.7z butts
$ stfu 7z a butts.7z asses
command failed with exit status 1:
7z a butts.7z asses

$ tail -n 5 /tmp/stfu.CoJ0vmJsqA/out_1627942118
Scan WARNINGS for files and folders:

asses : The system cannot find the file specified.

$ tail -n 5 /tmp/stfu.CoJ0vmJsqA/err_1627942118

WARNING: The system cannot find the file specified.

mpvs (sh/streamcrap)

invoke mpv with some extra flags suited for streamed sources.

mpv_watch (sh/streamcrap)

play some media in mpv with a bunch of unnecessary filters.

mpv_stream (sh/streamcrap)

watch a stream in mpv with a bunch of unnecessary filters.

twitch (sh/streamcrap)

watch a twitch stream in mpv with a bunch of unnecessary filters.

yt (sh/streamcrap)

watch a youtube video in mpv with a bunch of unnecessary filters. this can be given a full URL or just a video ID. remaining arguments are passed to mpv. there exist several variants for more specific use cases.

NOTE: there also exists a yt(1) program provided by the python3-yt package that i don't use.

ytll (sh/streamcrap)

watch a stream from youtube in mpv, etcetera etcetera. this is the low latency version that does not support seeking.


compute the summation of its arguments without forking processes. this relies on the shell's built-in arithmetic operators.

$ sum 1 2 3

TODO: consider renaming because sum(1) already exists.


collect the lastmost value of every key. the field separator can be given as its sole argument, it defaults to a single space otherwise.

$ echo "alpha=first\nbeta=second\nalpha=third" | sv =

this next example uses sv to only print the lastmost line matching a pattern in each file. in other words, it uses the filename printed by grep as the key in its key-value pairs.

$ cd ~/play/hash && grep -r 'ing$' . | sv :

TODO: rename because busybox(1) sv already exists.


output a given number of bytes from /dev/random.

$ trash 10 | xxp
3A A5 4F C7 6D 89 E7 D7 F7 0C

TODO: consider renaming because trash(1) already exists.


truncate text to fit within your terminal using the unicode character .

$ echo $COLUMNS
$ seq 1 100 | tr '\n' ' ' | trunc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31…


extract the contents of an archive file in one of many formats.

borrowed from prezto.


join paragraphs into one line each.


transform the contents of a variable to lowercase.


transform the contents of a variable to uppercase.


wat — a better and recursive which/whence. for zsh only.

written by leah2.


clear the screen and its scrollback, then print a high-contrast horizontal line. using this, you'll know with absolute certainty that you're looking at the top of your history, and that your terminal's scrollback didn't cap out and eat text.

TODO: rename because wipe(1) already exists.


act like xxd -p, but nicely formatted.

TODO: support -r (reverse) argument.

$ xxd -p ~/rc/install | head -n2
$ xxp ~/rc/install | head -n2
23 21 2F 75 73 72 2F 62 69 6E 2F 65 6E 76 20 73
68 0A 23 20 74 68 69 73 20 73 63 72 69 70 74 20


dummy (zshrc)

return 0, ignoring arguments.

dirprev (zshrc)

rotate and change to the previous directory in the directory stack without consuming the prompt.

dirnext (zshrc)

rotate and change to the next directory in the directory stack without consuming the prompt.

dirup (zshrc)

change to the parent directory of the current working directory without consuming the prompt.

dirview (zshrc)

use a fuzzy finder to select a recent directory in the directory stack and change to it without consuming the prompt.

OMFG (zshrc)

silence stdout.

STFU (zshrc)

silence stderr.

WHOA (zshrc)

expand to several C/C++ flags to ease development.

WHEE (zshrc)

WHOA but for C++ (specifically g++) only.

WELP (zshrc)

expand to C++ flags to enable a C++-as-C facade.

tw (zshrc)

invoke twitch as a job with both stdout and stderr silenced.

reload (zshrc)

reload zsh by wiping temp files, recompiling rc files, and replacing the current process with a new zsh process.

dummy (bashrc)

return 0, ignoring arguments.

reload (bashrc)

TODO: respect initctl like in .zshrc.

ADDPATH (shrc)

append a directory to $PATH if it isn't already present.

fils (shrc)

(GNU du) display human-friendly filesizes for the files in a directory.

lsa (shrc)

(GNU ls) list files with directories and dotfiles ordered first.

perlu (shrc)

invoke perl expecting files with UTF-8 encoding.

rgn (shrc)

invoke ripgrep without respecting .gitignore files.

cms (shrc)

invoke cryptominisat5 with less noise.

curls (shrc)

invoke curl with less noise.

get (shrc)

retrieve the most recent files from the default branch of a git repository, and not much else.

gs (shrc)

invoke git's status subcommand.

TODO: consider renaming because gs(1) already exists.

gd (shrc)

invoke git's diff subcommand with fewer lines of context.

gds (shrc)

display difference stats from git.

gl (shrc)

invoke git's log subcommand with a single line per commit.

TODO: consider renaming because gl(1) already exists.

glo (shrc)

navigate git's commit tree succinctly.

g1 (shrc)

display the most recent git commit.

gr (shrc)

display remote git repositories verbosely.

gb (shrc)

display the current git branch.

NOTE: there also exists a gb(1) program provided by the gb package that i don't use.

gdp (shrc)

invoke gd to diff a commit from its parent. the commit defaults to "HEAD".

revend (shrc)

reverse the 4-byte endianness of a single file. this is an in-place operation!

clone (shrc)

invoke rsync suitably for creating virtually indistinguishable copies of files.

aligntabs (shrc)

align tab-delimited fields in stdin.

crawla (shrc)

play Dungeon Crawl: Stone Soup through ssh on the akrasiac server.

crawlz (shrc)

play Dungeon Crawl: Stone Soup through ssh on the develz server.

eahead (shrc)

deprecated name for ea head.

eaget (shrc)

deprecated name for ea get.

eaput (shrc)

deprecated name for ea put.

eamove (shrc)

deprecated name for ea move.

eacopy (shrc)

deprecated name for ea copy.

eadelete (shrc)

deprecated name for ea delete.

eamv (shrc)

invoke ea move.

eacp (shrc)

invoke ea copy.

earm (shrc)

invoke ea delete.

ll (shrc)

list files verbosely, fancily, ordered, but not recursively.

diff (shrc)

use git's diff subcommand for general diffing.

gc (shrc)

columnize text by using git's column subcommand.

TODO: consider renaming because gc(1) already exists.

counts (shrc)

count files in the current directory, including files found recursively.

exts (shrc)

count and sort file extensions in the current directory, including files found recursively.

nocom (shrc)

strip single-line C-like and shell-like comments.

jrep (shrc)

extract strings comprised of basic ASCII or Japanese codepoints.

bomb (shrc)

add a Byte-Order Mark to a file.

cleanse (shrc)

strip unprintable and non-ASCII characters.

double (shrc)

print every line twice.
print every line twice.

NOTE: there also exists a double(1) program provided by the plotutils package that i don't use.

katagana (shrc)

convert katakana codepoints to their equivalent hiragana.

this is occasionally useful when translating debug text from ancient games.

picky (shrc)

list pacman packages that were manually installed and are not in some common package groups. this list can be used to assist later reinstalls.

unused (shrc)

list pacman packages that weren't installed explicitly and don't satisfy any dependencies. this list can be used to free up some disk space.

makepkgf (shrc)

make the freakin' package!

rakef (shrc)

make the freakin' gem!

pl (shrc)

print each argument on its own line.


script preference zsh bash dash ash
archive zsh
argc sh
arith zsh
arrays false
aur bash
autosync zsh
bak sh
baknow sh
baks sh
bin zsh
busiest zsh
colors bash
colors2 bash
compile zsh
confirm sh
countdiff sh
cutv zsh
dated sh
days sh
decently sh
dfu sh
disowned sh
document dash
e sh
ea sh
echo2 sh
explore sh
ff sh
ghmd sh
glug dash
grop sh
grop4 sh
has sh
have sh
hex zsh
ify sh
is_empty bash
isup sh
join2 sh
lsarchive zsh
maybesudo sh
minutemaid dash
monitor zsh
morecolors bash
noccom sh
note sh
now sh
oxo sh
pacbm sh
pause sh
pegg sh
pippy sh
pre sh
preload false
psbm sh
randir sh
refresh sh
rot13 sh
rs zsh
running sh
sc bash
scount sh
scramble sh
scropt bash
shcom sh
shelly perl n/a n/a n/a n/a
similar sh
slit dash
slitt dash
sortip sh
sram zsh
stfu sh
streamcrap false
sum sh
sv sh
trash sh
trunc sh
unarchive zsh
unwrap sh
v_domap sh
v_lower sh
v_upper sh
wat zsh
wipe sh
witch sh
xxp sh