diff options
Diffstat (limited to 'bin')
-rwxr-xr-x | bin/backup | 128 | ||||
-rwxr-xr-x | bin/brightness | 13 | ||||
-rwxr-xr-x | bin/clamp | 74 | ||||
-rwxr-xr-x | bin/color | 204 | ||||
-rwxr-xr-x | bin/copy | 67 | ||||
-rwxr-xr-x | bin/e | 79 | ||||
-rwxr-xr-x | bin/email | 74 | ||||
-rwxr-xr-x | bin/gc | 105 | ||||
-rwxr-xr-x | bin/grun | 102 | ||||
-rwxr-xr-x | bin/max | 61 | ||||
-rwxr-xr-x | bin/min | 61 | ||||
-rwxr-xr-x | bin/mkdtemp | 24 | ||||
-rwxr-xr-x | bin/mkstemp | 24 | ||||
-rwxr-xr-x | bin/msg | 90 | ||||
-rwxr-xr-x | bin/open | 101 | ||||
-rwxr-xr-x | bin/pre | 72 | ||||
-rwxr-xr-x | bin/print | 151 | ||||
-rwxr-xr-x | bin/qr | 58 | ||||
-rwxr-xr-x | bin/rfc | 117 | ||||
-rwxr-xr-x | bin/tmpname | 52 | ||||
-rwxr-xr-x | bin/uuid | 53 | ||||
-rwxr-xr-x | bin/with-email | 84 | ||||
-rwxr-xr-x | bin/without-env | 76 | ||||
l--------- | bin/xdg-open | 1 | ||||
-rwxr-xr-x | bin/xmpp | 89 |
25 files changed, 1960 insertions, 0 deletions
diff --git a/bin/backup b/bin/backup new file mode 100755 index 0000000..cab37dc --- /dev/null +++ b/bin/backup @@ -0,0 +1,128 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + backup [-v] [-C COMMENT] ARCHIVE_TAG + backup -h + EOF +} + +help() { + cat <<-'EOF' + + + Options: + -v enable verbose mode, useful for + interactive sessions + -C COMMENT the comment text to be attached to the archive + -h, --help show this message + + ARCHIVE_TAG the tag used to create the new + backup (default: "cronjob") + + + The repository is expected to have been created with: + + $ borg init -e repokey-blake2 + + The following environment variables are expected to be exported: + + $BORG_PASSCOMMAND + $BORG_REPO + $BORG_REMOTE_PATH + + Password-less SSH access is required, usually done via adding + ~/.ssh/id_rsa.pub to suyin:.ssh/authorized_keys. + + + Examples: + + Run backup from cronjob: + + $ backup cronjob + + Create backup with comment, and verbose mode active: + + $ backup -vC 'The backup has a comment' my-backup + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +VERBOSE_FLAGS='' +COMMENT='' +while getopts 'vC:h' flag; do + case "$flag" in + v) + VERBOSE_FLAGS='--verbose --progress' + ;; + C) + COMMENT="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s\n' "$2" >&2 + usage >&2 + exit 2 + fi +} + +ARCHIVE_TAG="${1:-}" +assert_arg "$ARCHIVE_TAG" 'ARCHIVE_TAG' + + +finish() { + STATUS=$? + printf '\n>>>\n>>> exit status: %s\n>>>\n\n' "$STATUS" >&2 +} +trap finish EXIT + +run() { + borg create \ + $VERBOSE_FLAGS \ + --comment "$COMMENT" \ + --exclude ~/.cache/ \ + --exclude ~/Downloads/ \ + --stats \ + --compression lzma,9 \ + "::{hostname}-{now}-$ARCHIVE_TAG" \ + ~/ + STATUS=$? + + if [ "$STATUS" = 0 ] || [ "$STATUS" = 1 ]; then + echo 'WARNING, but no ERROR.' >&2 + return 0 + else + return "$STATUS" + fi +} + +run || exit $? diff --git a/bin/brightness b/bin/brightness new file mode 100755 index 0000000..8e178ad --- /dev/null +++ b/bin/brightness @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu + +BRIGHTNESS_DIFF="$1" + +DEVICE="$(cat "$XDG_CONFIG_HOME"/backlight-device)" +HANDLER="/sys/class/backlight/$DEVICE" + +OLD_BRIGHTNESS="$(cat "$HANDLER"/brightness)" +MAX_BRIGHTNESS="$(cat "$HANDLER"/max_brightness)" +SUM=$((OLD_BRIGHTNESS + BRIGHTNESS_DIFF)) +NEW_BRIGHTNESS="$(clamp -- "$SUM" 0 "$MAX_BRIGHTNESS")" +echo "$NEW_BRIGHTNESS" > "$HANDLER"/brightness || sudo chmod 666 "$HANDLER/brightness" diff --git a/bin/clamp b/bin/clamp new file mode 100755 index 0000000..a40b823 --- /dev/null +++ b/bin/clamp @@ -0,0 +1,74 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + clamp NUMBER MIN MAX + clamp -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Clamp the NUMBER between MIN and MAX. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s\n\n' "$2" >&2 + usage >&2 + exit 2 + fi +} + +NUMBER="${1:-}" +MIN="${2:-}" +MAX="${3:-}" + +assert_arg "$NUMBER" 'NUMBER' +assert_arg "$MIN" 'MIN' +assert_arg "$MAX" 'MAX' + + +if [ "$MIN" -gt "$MAX" ]; then + printf 'MIN (%s) is greater then MAX (%s).\n' "$MIN" "$MAX" >&2 + exit 2 +fi + +min -- "$(max -- "$NUMBER" "$MIN")" "$MAX" diff --git a/bin/color b/bin/color new file mode 100755 index 0000000..0597278 --- /dev/null +++ b/bin/color @@ -0,0 +1,204 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + color -c COLOR TEXT + color -h + EOF +} + +help() { + cat <<-'EOF' + + + Options: + -c COLOR + -h, --help show this message + + + The available colors are: + EOF + list_colors | sed 's/^/ /' +} + + +END="\033[0m" + +black() { + BLACK="\033[0;30m" + printf "${BLACK}${1}${END}" +} + +blackb() { + BLACK_B="\033[1;30m" + printf "${BLACK_B}${1}${END}" +} + +blacki() { + BLACK_I="\033[0;90m" + printf "${BLACK_I}${1}${END}" +} + +white() { + WHITE="\033[0;37m" + printf "${WHITE}${1}${END}" +} + +whiteb() { + WHITE_B="\033[1;37m" + printf "${WHITE_B}${1}${END}" +} + +red() { + RED="\033[0;31m" + printf "${RED}${1}${END}" +} + +redb() { + RED_B="\033[1;31m" + printf "${RED_B}${1}${END}" +} + +green() { + GREEN="\033[0;32m" + printf "${GREEN}${1}${END}" +} + +greenb() { + GREEN_B="\033[1;32m" + printf "${GREEN_B}${1}${END}" +} + +yellow() { + YELLOW="\033[0;33m" + printf "${YELLOW}${1}${END}" +} + +yellowb() { + YELLOW_B="\033[1;33m" + printf "${YELLOW_B}${1}${END}" +} + +blue() { + BLUE="\033[0;34m" + printf "${BLUE}${1}${END}" +} + +blueb() { + BLUE_B="\033[1;34m" + printf "${BLUE_B}${1}${END}" +} + +bluei() { + BLUE_I="\033[0;94m" + printf "${BLUE_I}${1}${END}" +} + +purple() { + PURPLE="\033[0;35m" + printf "${PURPLE}${1}${END}" +} + + +purpleb() { + PURPLE_B="\033[1;35m" + printf "${PURPLE_B}${1}${END}" +} + +lightblue() { + LIGHT_BLUE="\033[0;36m" + printf "${LIGHT_BLUE}${1}${END}" +} + +lightblueb() { + LIGHT_BLUE_B="\033[1;36m" + printf "${LIGHT_BLUE_B}${1}${END}" +} + +COLOR_LIST=' +black +blackb +white +whiteb +red +redb +green +greenb +yellow +yellowb +blue +blueb +purple +purpleb +lightblue +lightblueb +blacki +bluei +' +list_colors() { + for c in $COLOR_LIST; do + printf '%s\n' "$("$c" "$c")" + done +} + + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'c:h' flag; do + case "$flag" in + c) + EXISTS=false + for c in $COLOR_LIST; do + if [ "$OPTARG" = "$c" ]; then + EXISTS=true + break + fi + done + if [ "$EXISTS" = false ]; then + printf 'Invalid color: %s\n' "$OPTARG" >&2 + exit 2 + fi + COLOR_FN="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s\n\n' "$2" >&2 + usage >&2 + exit 2 + fi +} + +TEXT="${1:-}" +assert_arg "$COLOR_FN" '-c COLOR' +assert_arg "$TEXT" 'TEXT' + + +"$COLOR_FN" "$TEXT" diff --git a/bin/copy b/bin/copy new file mode 100755 index 0000000..64e1e32 --- /dev/null +++ b/bin/copy @@ -0,0 +1,67 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + copy [-n] < STDIN + copy -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -n remove newlines + -h, --help show this message + + Examples: + + Copy numbers to clipboard: + seq 10 | copy + + Copy string without newline: + echo 'with automatic newline' | copy -n + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +TRIM=false +while getopts 'nh' flag; do + case "$flag" in + n) + TRIM=true + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +if [ "$TRIM" = true ]; then + cat - | tr -d '\n' | xclip -sel clip +else + cat - | xclip -sel clip +fi @@ -0,0 +1,79 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + e [FILE] + e -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help + + + Flexibly run a text editor, either directly on in a pipe. + + Examples: + + Edit "file.txt": + + $ e file.txt + + Manipulate the content of a pipe midway: + + $ seq 10 | e | grep 5 + + The editor used is either $VISUAL or $EDITOR, with a fallback to + vi in case any of those variables aren't defined. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + +CMD="${VISUAL:-${EDITOR:-vi}}" + +if [ ! -t 0 ]; then + F="$(mkstemp)" + cat > "$F" + exec 0</dev/tty + exec 3>&1 + exec 1>/dev/tty + $CMD "$F" + cat "$F" >&3 +else + $CMD "$@" +fi diff --git a/bin/email b/bin/email new file mode 100755 index 0000000..0a1fd15 --- /dev/null +++ b/bin/email @@ -0,0 +1,74 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + mail -s SUBJECT ADDRESS... < BODY + mail -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -s SUBJECT the email subject + -h, --help show this message + + ADDRESS the email addresses to send the email to + BODY the text to be sent as the body + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 's:h' flag; do + case "$flag" in + s) + SUBJECT="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + { + printf 'Missing %s.\n' "$2" + printf '\n' + usage + } >&2 + exit 2 + fi +} + +assert_arg "${SUBJECT:-}" '-s SUBJECT' +assert_arg "${1:-}" 'ADDRESS' + +printf 'Subject: %s\n\n%s' \ + "$(echo "$SUBJECT" | tr -d '\n')" \ + "$(cat)" | + msmtpq -a euandreh "$@" @@ -0,0 +1,105 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + gc + gc -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + +disk() { + df -h . | + awk 'NR == 2 { printf "%s - %s/%s\n", $4, $3, $2 }' +} + + +gc_guix() { + pass show velhinho/0-andreh-password | sudo -S guix system delete-generations + guix home delete-generations + guix gc -d +} + +gc_nohup() { + find ~/ -type f -name 'nohup.out' -exec rm -vf "{}" \; +} + +gc_trash() { + yes | trash-empty +} + +gc_tmpdir() { + find /tmp/ -type f -atime +10 -exec rm -vf "{}" \; ||: +} + +gc_docker() { + if command -v docker; then + yes | docker system prune -a + docker rmi "$(docker images -a -q)" ||: + docker rm "$(docker ps -a -f status=exited -q)" ||: + docker stop "$(docker ps -a -q)" ||: + docker rm "$(docker ps -a -q)" ||: + yes | docker volume prune + yes | docker container prune + fi +} + +gc_email() { + notmuch search --output=files --exclude=false tag:killed | + xargs -I{} rm -vf "{}" +} + + +BEFORE="$(disk)" +gc_guix +gc_nohup +gc_trash +gc_tmpdir +gc_docker +gc_email +wait +AFTER="$(disk)" + +printf 'Disk space:\n' +printf ' before: %s\n' "$BEFORE" +printf ' after: %s\n' "$AFTER" diff --git a/bin/grun b/bin/grun new file mode 100755 index 0000000..5884e9e --- /dev/null +++ b/bin/grun @@ -0,0 +1,102 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + grun [-r RECIPIENT] FILENAME -- COMMAND... + grun -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -r RECIPIENT the recipient to encrypt to. Can be given + multiple for multiple recipients. + -h, --help show this message + + COMMAND A command to be executed, that accepts input + in STDIN and emits result in STDOUT, and emits + errors as non-zero return codes. + FILENAME The GPG-encrypted file to be processed. If it + doesn't exist yet, it will be created. + + Examples: + + Edit "secrets.txt.gpg" using `vipe` and the default recipient: + + $ grun secrets.txt.gpg -- vipe + + Delete lines containing "FIXME" in todos.gpg: + + $ grun -r ABC123DEF321 todos.gpg -- sed '/FIXME/d' + + If COMMAND emits a non-zero return code, the file is left + unmodified. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'rh' flag; do + case "$flag" in + r) + RECIPIENTS_FLAG="${RECIPIENTS_FLAG:-} -r $OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s\n\n' "$2" >&2 + usage >&2 + exit 2 + fi +} + +FILENAME="${1:-}" +assert_arg "$FILENAME" 'FILENAME' +shift + +if [ "${1:-}" != '--' ]; then + printf 'Missing "--" separator\n\n' >&2 + usage >&2 + exit 2 +fi +shift + +assert_arg "${1:-}" 'COMMAND' + + +if [ ! -e "$FILENAME" ]; then + OUT="$(printf '' | "$@")" +else + OUT="$(gpg -dq "$FILENAME" | "$@")" +fi + +echo "$OUT" | gpg -e ${RECIPIENTS_FLAG:--r eu@euandre.org} | sponge "$FILENAME" @@ -0,0 +1,61 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + max NUMBER... + max -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Get the maximum number from the given values. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +if [ -z "${1:-}" ]; then + echo 0 + exit +fi + +N="$1" +for n in "$@"; do + N=$((N > n ? N : n)) +done +echo "$N" @@ -0,0 +1,61 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + min NUMBER... + min -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Get the minimun number from the given values. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +if [ -z "${1:-}" ]; then + echo 0 + exit +fi + +N="$1" +for n in "$@"; do + N=$((N < n ? N : n)) +done +echo "$N" diff --git a/bin/mkdtemp b/bin/mkdtemp new file mode 100755 index 0000000..9c7ddd8 --- /dev/null +++ b/bin/mkdtemp @@ -0,0 +1,24 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + mkstemp + mkstemp -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Create a new temporary file and echo its name back. + EOF +} + +name="$(tmpname)" +mkdir "$name" +echo "$name" diff --git a/bin/mkstemp b/bin/mkstemp new file mode 100755 index 0000000..ec92c14 --- /dev/null +++ b/bin/mkstemp @@ -0,0 +1,24 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + mkstemp + mkstemp -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Create a new temporary file and echo its name back. + EOF +} + +name="$(tmpname)" +touch "$name" +echo "$name" @@ -0,0 +1,90 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + msg -X XMPP_MESSAGE -s -S SOUND_MESSAGE -m EMAIL -D DESKTOP -b + msg -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -X XMPP_MESSAGE send XMPP using the `xmpp` command + -s play ~/Desktop/medium.ogg sound + -S SOUND_MESSAGE say SOUND_MESSAGE using `speak` + -m EMAIL_SUBJECT send email with EMAIL_SUBJECT and empty body + -D DESKTOP_MESSAGE the desktop message for `notify-send` + -b print terminal bell + -h, --help show this message + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +sound() { + play ~/Desktop/medium.ogg 2>/dev/null & +} + +ACTION_DONE=false +while getopts 'X:sS:m:D:bh' flag; do + case "$flag" in + X) + xmpp -m "$OPTARG" eu@euandreh.xyz + ACTION_DONE=true + ;; + s) + sound + ACTION_DONE=true + ;; + S) + echo "$OPTARG" | speak -v pt-BR + ACTION_DONE=true + ;; + m) + echo "" | email -s "$OPTARG" eu@euandre.org + ACTION_DONE=true + ;; + D) + notify-send "$OPTARG" + ACTION_DONE=true + ;; + b) + printf '\a' + ACTION_DONE=true + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done + +if [ "$ACTION_DONE" = false ]; then + sound + usage + help +fi + +wait diff --git a/bin/open b/bin/open new file mode 100755 index 0000000..df1ad56 --- /dev/null +++ b/bin/open @@ -0,0 +1,101 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + open FILE... + open -h +EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Examples: + + Open an HTML file on the current $BROWSER: + open index.html + + Open multiple PDF files (with zathura): + open *.pdf +EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +if [ -z "${1:-}" ]; then + usage >&2 + exit 2 +fi + +for f in "$@"; do + case "$f" in + *.ico|*.jpg|*.jpeg|*.png) + feh "$f" + ;; + https://www.youtube.com/watch*) + nohup mpv "$f" 1>&2 2>/dev/null & + ;; + *.flac|*.ogg|*.mkv|*.avi|*.mp4) + nohup mpv "$f" 1>&2 2>/dev/null & + ;; + http*|*.svg|*.html) + "$BROWSER" "$f" + ;; + gopher://*) + amfora "$f" + ;; + gemini://*) + telescope "$f" + ;; + *.pdf|*.djvu|*.ps|*.epub) + nohup zathura "$f" 1>&2 2>/dev/null & + ;; + *.txt) + less "$f" + ;; + *.midi) + timidity "$f" + ;; + mailto:*) + alot compose "$f" + ;; + *) + DIR="$(cd -- "$(dirname -- "$0")"; pwd)" + CMD="$(without-env PATH "$DIR" -- command -v xdg-open)" + "$CMD" "$f" + ;; + esac +done @@ -0,0 +1,72 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + pre [-c COLOR] PREFIX + pre -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -c COLOR ANSI color to be used on the prefix text + -h, --help show this message + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +COLOR='' +while getopts 'c:h' flag; do + case "$flag" in + c) + COLOR="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s\n\n' "$2" >&2 + usage >&2 + exit 2 + fi +} + +PREFIX="${1:-}" +assert_arg "$PREFIX" 'PREFIX' + +while read -r line; do + if [ -z "$COLOR" ]; then + printf '%s: %s\n' "$PREFIX" "$line" + else + printf '%s: %s\n' "$(color -c "$COLOR" "$PREFIX")" "$line" + fi +done diff --git a/bin/print b/bin/print new file mode 100755 index 0000000..735d8ba --- /dev/null +++ b/bin/print @@ -0,0 +1,151 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + print [-d] [-q QUALITY] [FILE...] + print -h +EOF +} + +help() { + cat <<-'EOF' + + Options: + -d print duplex/double-sided + -q QUALITY choose the print quality, either: + low, medium (default) or high. + -h, --help show this message + + Examples: + + Print the given PostScript file with default quality: + $ print f1.ps + + Print multiple PDF files with high quality: + $ print -dq high *.pdf + + Print the file from STDIN, double-sided: + $ print -d < f2.ps + + Print multiple source code files: + $ print src/*.{c,h} +EOF +} + +mkdtemp() { + name="$(echo 'mkstemp(template)' | + m4 -D template="${TMPDIR:-/tmp}/m4-tmpname.")" + rm -f "$name" + mkdir "$name" + echo "$name" +} + +n_pages() { + pdftk "$1" dump_data | awk '/NumberOfPages/ { print $2 }' +} + +main() { + if file -b "$FILE" | grep -q PostScript; then + ps2pdf "$FILE" "$NEWDIR"/in.pdf + elif file -b "$FILE" | grep -q PDF; then + cp "$FILE" "$NEWDIR"/in.pdf + else + enscript -o- "$FILE" | ps2pdf - "$NEWDIR"/in.pdf + fi + cd "$NEWDIR" + + if [ -z "$DUPLEX" ]; then + lp in.pdf + cd - > /dev/null + return + fi + + if [ "$(n_pages in.pdf)" = '1' ]; then + lp in.pdf + return + fi + + pdftk A=in.pdf cat Aodd output odd.pdf + pdftk A=in.pdf cat Aeven output even.pdf + + NODD="$(n_pages odd.pdf)" + NEVEN="$(n_pages even.pdf)" + + printf 'Printing odd pages...\n' >&2 + lp odd.pdf + printf 'Has printing finished yet? Once it does, reload the pages and hit it enter to continue. ' + read -r < /dev/tty + lp even.pdf + + if [ "$NODD" != "$NEVEN" ]; then + printf '\n' | lp + fi + + cd - > /dev/null +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +lpoptions -o PrintQuality=standard +DUPLEX= +while getopts 'dq:h' flag; do + case "$flag" in + d) + DUPLEX=1 + ;; + q) + case "$OPTARG" in + low) + lpoptions -o PrintQuality=draft + ;; + medium) + lpoptions -o PrintQuality=standard + ;; + high) + lpoptions -o PrintQuality=high + ;; + *) + echo "Bad QUALITY option: \"$OPTARG\"" >&2 + exit 2 + ;; + esac + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +NEWDIR="$(mkdtemp)" +if [ -z "${1:-}" ]; then + FILE="$NEWDIR"/STDIN + cat - > "$FILE" + main +else + for f in "$@"; do + FILE="$f" + main + done +fi @@ -0,0 +1,58 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + qr [-s PIXEL_SIZE] + qr -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -s PIXEL_SIZE size of the pixel (default 10) + -h, --help show this help message + + Read data from STDIN and present a QR image with said data. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +PIXEL_SIZE=10 +while getopts 's:h' flag; do + case "$flag" in + s) + PIXEL_SIZE="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + +cat | qrencode -s "$PIXEL_SIZE" -o- | feh - @@ -0,0 +1,117 @@ +#!/bin/sh +set -eu + +TARBALL_URL='https://www.rfc-editor.org/in-notes/tar/RFC-all.tar.gz' + +usage() { + cat <<-'EOF' + Usage: + rfc [-w] RFC_NUMBER + rfc -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -w Show the path to the RFC file instead of displaying + its contents. + -h, --help show this message + + Lookup the given RFC + in $XDG_DATA_HOME/doc/rfc/ (defaults to ~/.local/share), + and feed it into the $PAGER, akin to doing: + + $ $PAGER $XDG_DATA_HOME/doc/rfc/rfc$RFC_NUMBER.txt + + If the $XDG_DATA_HOME/doc/rfc/ directory doesn't exist, it tries to + create it by downloading the latest RFC tarball [0] and placing all .txt + files there. + EOF + + printf '\n[0]: %s\n' "$TARBALL_URL" +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'wh' flag; do + case "$flag" in + w) + WHERE=true + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +RFC_NUMBER="${1:-}" +if [ -z "$RFC_NUMBER" ]; then + echo 'Missing argument RFC_NUMBER' >&2 + usage >&2 + exit 2 +fi + +D="${XDG_DATA_HOME:-$HOME/.local/share}/doc/rfc" +if [ ! -e "$D" ]; then + printf 'RFC directory does not exist:\n\t%s/\n\n' "$D" + printf 'Do you want to download the files to create it? [Y/n] ' + read -r yesno + if [ "$yesno" != 'n' ] && [ "$yesno" != 'N' ]; then + CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/rfc-cli" + mkdir -p "$CACHE_DIR" + wget -cO "$CACHE_DIR"/RFC-all.tar.gz "$TARBALL_URL" + rm -rf "$CACHE_DIR/tmp" + mkdir -p "$CACHE_DIR/tmp" + tar \ + -C "$CACHE_DIR/tmp" \ + -xvf "$CACHE_DIR"/RFC-all.tar.gz \ + --wildcards \ + 'rfc*.txt' + mkdir -p "$(dirname "$D")" + mv "$CACHE_DIR/tmp" "$D" + fi +fi + +F="$D/rfc${RFC_NUMBER}.txt" +if [ ! -e "$F" ]; then + printf 'Given RFC_NUMBER "%s" does not exist at:\n%s\n' \ + "$RFC_NUMBER" "$F" >&2 + exit 2 +fi + +if [ "${WHERE:-}" = true ]; then + printf '%s\n' "$F" + exit +fi + +view() { + if [ -t 1 ]; then + ${PAGER:-cat} + else + cat + fi +} + +view < "$F" diff --git a/bin/tmpname b/bin/tmpname new file mode 100755 index 0000000..d83fc87 --- /dev/null +++ b/bin/tmpname @@ -0,0 +1,52 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + tmpname + tmpname -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Generate a temporary name. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +echo "${TMPDIR:-/tmp}/uuid-tmpname with spaces.$(uuid)" diff --git a/bin/uuid b/bin/uuid new file mode 100755 index 0000000..74d0fba --- /dev/null +++ b/bin/uuid @@ -0,0 +1,53 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + uuid + uuid -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Generate UUID from /dev/random. + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +od -xN20 /dev/random | + awk 'NR == 1 { OFS="-"; print $2$3,$4,$5,$6,$7$8$9; exit }' diff --git a/bin/with-email b/bin/with-email new file mode 100755 index 0000000..9d6326b --- /dev/null +++ b/bin/with-email @@ -0,0 +1,84 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + with-email [-s SUBJECT] COMMAND... + with-email -h + EOF +} + +help() { + cat <<-'EOF' + + Options: + -s SUBJECT set the subject of the email + -h, --help show this message + + COMMAND the command to be wrapped + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +SUBJECT='NO SUBJECT' +while getopts 's:h' flag; do + case "$flag" in + s) + SUBJECT="$OPTARG" + ;; + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s\n\n' "$2" >&2 + usage >&2 + exit 2 + fi +} + +assert_arg "${1:-}" 'COMMAND...' + +now() { + date '+%Y-%m-%dT%H:%M:%S%Z' +} + +OUT="$(mkstemp)" +{ + printf 'Running command: %s\n' "$*" + printf 'Starting at: %s\n' "$(now)" + printf '\n' + + STATUS=0 + "$@" 2>&1 || STATUS=$? + + printf '\n' + printf '\nFinished at: %s\n' "$(now)" +} 2>&1 1>"$OUT" + +email -s "(exit status: $STATUS) - $SUBJECT" eu@euandre.org < "$OUT" diff --git a/bin/without-env b/bin/without-env new file mode 100755 index 0000000..45c41ca --- /dev/null +++ b/bin/without-env @@ -0,0 +1,76 @@ +#!/bin/sh +set -eu + +usage() { + cat <<-'EOF' + Usage: + without-env ENVVAR PATH -- COMMAND... + without-env [-h] + EOF +} + +help() { + cat <<-'EOF' + + Options: + -h, --help show this message + + Examples: + + Execute "command -V" filtering ~/bin, to get where "w3m" is + in $PATH, other than ~/bin: + $ without-env PATH ~/bin -- command -v w3m + + Compile foo.c, excluding ~/.local/include + from $C_INCLUDE_PATH: + $ without-env C_INCLUDE_PATH ~/.local/include -- cc -co foo.o foo.c + EOF +} + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + *) + ;; + esac +done + +while getopts 'h' flag; do + case "$flag" in + h) + usage + help + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + +assert_arg() { + if [ -z "$1" ]; then + printf 'Missing %s\n' "$2" >&2 + exit 2 + fi +} + +assert_arg "${1:-}" 'ENVVAR' +assert_arg "${2:-}" 'PATH' +assert_arg "${3:-}" '--' + +eval "export $1=\"\$(echo \"\$$1\" | sed \"s|\$2:||g\")\"" +shift # drop $1 +shift # drop $2 +shift # drop -- + +"$@" diff --git a/bin/xdg-open b/bin/xdg-open new file mode 120000 index 0000000..ce4a72b --- /dev/null +++ b/bin/xdg-open @@ -0,0 +1 @@ +open
\ No newline at end of file diff --git a/bin/xmpp b/bin/xmpp new file mode 100755 index 0000000..472e9ca --- /dev/null +++ b/bin/xmpp @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +import os +import sys +import getopt +import logging +import slixmpp + +USAGE = """\ +Usage: + xmpp [-d] [-F FROM_JID] -m MESSAGE TO_JID... + xmpp -h""" + +HELP = """ +Options: + -d run in DEBUG mode + -m MESSAGE the text of the message to be sent + -h, --help show this message + + FROM_JID the address used to send the message from + TO_JID the addresses where to send the message to""" + +class SendMsgBot(slixmpp.ClientXMPP): + def __init__(self, jid, password, on_start): + slixmpp.ClientXMPP.__init__(self, jid, password) + + self.on_start = on_start + self.add_event_handler("session_start", self.start) + + def start(self, event): + self.on_start(self) + self.disconnect(wait=True) + +def main(): + logging.basicConfig(level=logging.INFO) + from_ = "bot@euandreh.xyz" + message = "" + + for s in sys.argv: + if s == "--": + break + elif s == "--help": + print(USAGE) + print(HELP) + sys.exit() + + try: + opts, args = getopt.getopt(sys.argv[1:], 'm:F:dh') + except getopt.GetoptError as err: + print(err, file=sys.stderr) + print(USAGE, file=sys.stderr) + sys.exit(2) + for o, a in opts: + if o == "-m": + message = a + elif o == "-F": + from_ = a + elif o == "-d": + logging.basicConfig(level=logging.DEBUG) + elif o == "-h": + print(USAGE) + print(HELP) + sys.exit() + else: + assert False, "unhandled option" + + if message == "": + print("Missing -m MESSAGE", file=sys.stderr) + print(USAGE, file=sys.stderr) + sys.exit(2) + + if args == []: + print("Missing TO_JID", file=sys.stderr) + print(USAGE, file=sys.stderr) + sys.exit(2) + + passcmd = "pass show VPS/kuvira/XMPP/" + from_ + " | head -n1 | tr -d '\\n'" + password = os.popen(passcmd).read() + + def on_start(self): + for to in args: + self.send_message(mto=to, mbody=message, mtype='chat') + + xmpp = SendMsgBot(from_, password, on_start) + xmpp.connect() + xmpp.process(forever=False) + +if __name__ == "__main__": + main() |