~dricottone/my-utils

1aabb6efbc48286734905b3982be19076766b1b3 — Dominic Ricottone 2 years ago 8b4fb74
Refactored code into multiple 'packages'. One day these may be
independently installable. For now it's just an organization method.

Rewrote main README and added per-package READMEs.

Also: bug fix on whiched and whichvi. They formerly propogated an error
if $EDITOR or $VISUAL were set to a non-existant executable. Also
improved the inline documentation.
90 files changed, 832 insertions(+), 492 deletions(-)

M Makefile
M README.md
A archives/Makefile
A archives/README.md
R bash-completion/mybashcompletion.bash => archives/completion.bash
R src/epub => archives/epub
R src/mktar => archives/mktar
R src/rmtar => archives/rmtar
R src/rmzip => archives/rmzip
R src/tarcat => archives/tarcat
R src/tarls => archives/tarls
A archives/test_init.sh
R tests/compression_test.sh => archives/test_mktar_tarcat.sh
A archives/test_untar.sh
R src/untar => archives/untar
R src/zipls => archives/zipls
A containers/Makefile
A containers/README.md
R src/docker-clean => containers/docker-clean
R src/docker-get-all => containers/docker-get-all
R src/docker-get-all-containers => containers/docker-get-all-containers
R src/docker-get-all-services => containers/docker-get-all-services
R src/docker-get-exited => containers/docker-get-exited
R src/docker-restart => containers/docker-restart
R src/docker-up => containers/docker-up
A containers/swarm-test
A containers/test_init.sh
A containers/test_swarm-test.sh
A core/Makefile
A core/completion.bash
R src/ctdir => core/ctdir
R src/debom => core/debom
R src/enumerate => core/enumerate
R src/git-set-remotes => core/git-set-remotes
R src/mkbak => core/mkbak
R src/mylib.bash => core/mylib.bash
R src/myminiparse.sh => core/myminiparse.sh
R src/myparse.bash => core/myparse.bash
R src/rand => core/rand
R src/rebom => core/rebom
R src/rmold => core/rmold
R src/start-at => core/start-at
R src/stop-at => core/stop-at
A core/test_ctdir.sh
A core/test_debom_rebom.sh
A core/test_init.sh
A core/test_whichcat_whichhead.sh
A core/test_whiched_whichvi.sh
R src/unittest => core/unittest
R src/unittest-color.awk => core/unittest-color.awk
R src/vimsplit => core/vimsplit
R src/whichcat => core/whichcat
R src/whiched => core/whiched
R src/whichhead => core/whichhead
R src/whichvi => core/whichvi
R src/wttr => core/wttr
A display/Makefile
A display/README.md
R src/check-x => display/check-x
R src/resetx => display/resetx
A display/test_check-x.sh
A emulation/Makefile
A emulation/README.md
R src/android-emulator => emulation/android-emulator
R src/qemu-test => emulation/qemu-test
A emulation/test_qemu-test.sh
A games/Makefile
A games/README.md
R src/whisper => games/whisper
A network/Makefile
A network/README.md
R src/fw-status => network/fw-status
R src/pingable => network/pingable
R src/vpn-off => network/vpn-off
R src/vpn-on => network/vpn-on
R src/wg-off => network/wg-off
R src/wg-on => network/wg-on
R src/wg-status => network/wg-status
R src/wg-test => network/wg-test
A sound/Makefile
A sound/README.md
R src/pactl-get-running-sink => sound/pactl-get-running-sink
R src/pactl-mute => sound/pactl-mute
R src/pactl-volume-down => sound/pactl-volume-down
R src/pactl-volume-printf => sound/pactl-volume-printf
R src/pactl-volume-up => sound/pactl-volume-up
D tests/bom_test.sh
D tests/ctdir_test.sh
D tests/init.sh
D tests/which_test.sh
M Makefile => Makefile +40 -112
@@ 1,123 1,51 @@

BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

install: clean
	install -m755 src/mylib.bash $(LIB_DIR)/mylib.bash
	install -m755 src/myparse.bash $(LIB_DIR)/myparse.bash
	install -m755 src/myminiparse.sh $(LIB_DIR)/myminiparse.sh
	install -m755 src/unittest-color.awk $(LIB_DIR)/unittest-color.awk
.PHONY: install uninstall test clean

	install -m755 src/android-emulator $(BIN_DIR)/android-emulator
	install -m755 src/check-x $(BIN_DIR)/check-x
	install -m755 src/ctdir $(BIN_DIR)/ctdir
	install -m755 src/debom $(BIN_DIR)/debom
	install -m755 src/docker-clean $(BIN_DIR)/docker-clean
	install -m755 src/docker-get-all $(BIN_DIR)/docker-get-all
	install -m755 src/docker-get-exited $(BIN_DIR)/docker-get-exited
	install -m755 src/docker-restart $(BIN_DIR)/docker-restart
	install -m755 src/docker-up $(BIN_DIR)/docker-up
	install -m755 src/enumerate $(BIN_DIR)/enumerate
	install -m755 src/epub $(BIN_DIR)/epub
	install -m755 src/fw-status $(BIN_DIR)/fw-status
	install -m755 src/mkbak $(BIN_DIR)/mkbak
	install -m755 src/mktar $(BIN_DIR)/mktar
	install -m755 src/pactl-get-running-sink $(BIN_DIR)/pactl-get-running-sink
	install -m755 src/pactl-mute $(BIN_DIR)/pactl-mute
	install -m755 src/pactl-volume-down $(BIN_DIR)/pactl-volume-down
	install -m755 src/pactl-volume-printf $(BIN_DIR)/pactl-volume-printf
	install -m755 src/pactl-volume-up $(BIN_DIR)/pactl-volume-up
	install -m755 src/pingable $(BIN_DIR)/pingable
	install -m755 src/qemu-test $(BIN_DIR)/qemu-test
	install -m755 src/rand $(BIN_DIR)/rand
	install -m755 src/rebom $(BIN_DIR)/rebom
	install -m755 src/resetx $(BIN_DIR)/resetx
	install -m755 src/rmold $(BIN_DIR)/rmold
	install -m755 src/rmtar $(BIN_DIR)/rmtar
	install -m755 src/rmzip $(BIN_DIR)/rmzip
	install -m755 src/start-at $(BIN_DIR)/start-at
	install -m755 src/stop-at $(BIN_DIR)/stop-at
	install -m755 src/tarcat $(BIN_DIR)/tarcat
	install -m755 src/tarls $(BIN_DIR)/tarls
	install -m755 src/unittest $(BIN_DIR)/unittest
	install -m755 src/untar $(BIN_DIR)/untar
	install -m755 src/vimsplit $(BIN_DIR)/vimsplit
	install -m755 src/vpn-off $(BIN_DIR)/vpn-off
	install -m755 src/vpn-on $(BIN_DIR)/vpn-on
	install -m755 src/wg-off $(BIN_DIR)/wg-off
	install -m755 src/wg-on $(BIN_DIR)/wg-on
	install -m755 src/wg-status $(BIN_DIR)/wg-status
	install -m755 src/wg-test $(BIN_DIR)/wg-test
	install -m755 src/whichcat $(BIN_DIR)/whichcat
	install -m755 src/whiched $(BIN_DIR)/whiched
	install -m755 src/whichhead $(BIN_DIR)/whichhead
	install -m755 src/whichvi $(BIN_DIR)/whichvi
	install -m755 src/whisper $(BIN_DIR)/whisper
	install -m755 src/wttr $(BIN_DIR)/wttr
	install -m755 src/zipls $(BIN_DIR)/zipls
define subdir_make
	cd $(1) && BIN_DIR=$(BIN_DIR) LIB_DIR=$(LIB_DIR) COMP_DIR=$(COMP_DIR) make $(2)
	@echo ""
endef

uninstall:
	rm $(LIB_DIR)/mylib.bash
	rm $(LIB_DIR)/myparse.bash
	rm $(LIB_DIR)/myminiparse.sh
	rm $(LIB_DIR)/unittest-color.awk
install:
	$(call subdir_make,core,install)
	$(call subdir_make,archives,install)
	$(call subdir_make,containers,install)
	$(call subdir_make,display,install)
	$(call subdir_make,emulation,install)
	$(call subdir_make,games,install)
	$(call subdir_make,network,install)
	$(call subdir_make,sound,install)

	rm $(BIN_DIR)/android-emulator
	rm $(BIN_DIR)/check-x
	rm $(BIN_DIR)/ctdir
	rm $(BIN_DIR)/debom
	rm $(BIN_DIR)/docker-clean
	rm $(BIN_DIR)/docker-get-all
	rm $(BIN_DIR)/docker-get-exited
	rm $(BIN_DIR)/docker-restart
	rm $(BIN_DIR)/docker-up
	rm $(BIN_DIR)/epub
	rm $(BIN_DIR)/enumerate
	rm $(BIN_DIR)/fw-status
	rm $(BIN_DIR)/mkbak
	rm $(BIN_DIR)/mktar
	rm $(BIN_DIR)/pactl-get-running-sink
	rm $(BIN_DIR)/pactl-mute
	rm $(BIN_DIR)/pactl-volume-down
	rm $(BIN_DIR)/pactl-volume-printf
	rm $(BIN_DIR)/pactl-volume-up
	rm $(BIN_DIR)/pingable
	rm $(BIN_DIR)/qemu-test
	rm $(BIN_DIR)/rand
	rm $(BIN_DIR)/rebom
	rm $(BIN_DIR)/resetx
	rm $(BIN_DIR)/rmold
	rm $(BIN_DIR)/rmtar
	rm $(BIN_DIR)/rmzip
	rm $(BIN_DIR)/start-at
	rm $(BIN_DIR)/stop-at
	rm $(BIN_DIR)/tarcat
	rm $(BIN_DIR)/tarls
	rm $(BIN_DIR)/unittest
	rm $(BIN_DIR)/untar
	rm $(BIN_DIR)/vimsplit
	rm $(BIN_DIR)/vpn-off
	rm $(BIN_DIR)/vpn-on
	rm $(BIN_DIR)/wg-off
	rm $(BIN_DIR)/wg-on
	rm $(BIN_DIR)/wg-status
	rm $(BIN_DIR)/wg-test
	rm $(BIN_DIR)/whichcat
	rm $(BIN_DIR)/whiched
	rm $(BIN_DIR)/whichhead
	rm $(BIN_DIR)/whichvi
	rm $(BIN_DIR)/whisper
	rm $(BIN_DIR)/wttr
	rm $(BIN_DIR)/zipls
uninstall:
	$(call subdir_make,core,uninstall)
	$(call subdir_make,archives,uninstall)
	$(call subdir_make,containers,uninstall)
	$(call subdir_make,display,uninstall)
	$(call subdir_make,emulation,uninstall)
	$(call subdir_make,games,uninstall)
	$(call subdir_make,network,uninstall)
	$(call subdir_make,sound,uninstall)

test: clean
	#shellcheck src/*.bash src/*.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh
	sh tests/init.sh
	sh tests/compression_test.sh
	sh tests/ctdir_test.sh
	sh tests/which_test.sh
	sh tests/bom_test.sh
	$(call subdir_make,core,clean)
	$(call subdir_make,archives,clean)
	$(call subdir_make,containers,clean)
	$(call subdir_make,display,clean)
	$(call subdir_make,emulation,clean)
	$(call subdir_make,games,clean)
	$(call subdir_make,network,clean)
	$(call subdir_make,sound,clean)

clean:
	rm -rf tests/static tests/temp_enumerate
	$(call subdir_make,core,clean)
	$(call subdir_make,archives,clean)
	$(call subdir_make,containers,clean)
	$(call subdir_make,display,clean)
	$(call subdir_make,emulation,clean)
	$(call subdir_make,games,clean)
	$(call subdir_make,network,clean)
	$(call subdir_make,sound,clean)


M README.md => README.md +13 -101
@@ 4,115 4,27 @@ A set of scripts that I use frequently. Written in a mix of shell (some POSIX
sh, some bash), sed, awk, and so on. Any dependencies *beyond* the POSIX
standard and inter-dependency are noted.


## General-Use Scripts

Executable      |Description                                                   |Extra Dependencies
:---------------|:-------------------------------------------------------------|:------------------------------------------
check-x         |Check if an X11 server is running
ctdir           |Count entries in a target directory(ies)
debom           |Remove BOM from a target file                                 |`bash`
enumerate       |Rename files in current directory into sequential numbers     |`bash`
epub            |Dumps HTML from an 'epub' e-book archive                      |`bash`, `zipinfo`, `unzip`, `w3m`
fw-status       |Print current firewall status                                 |`ufw`
git-set-remotes |Set all git remotes for my public repositories                |`git`
mkbak           |Create a backup of a target file                              |`bash`
mktar           |Wrapper around `tar` for easier compression                   |`bash` *
pingable        |Check if an address/name is ping-able                         |`ping`
rand            |Get a random number within an inclusive range                 |`bash`, `shuf`
rebom           |Add BOM to a target file
resetx          |Reset X server monitor configuration                          |`xrandr`
rmold           |Delete old files
rmtar           |Delete 'tar' archive files
rmzip           |Delete 'zip' archive files
start-at        |After a pattern is matched, re-print                          |GNU or New (AT&T) `awk`
stop-at         |Re-print until a pattern is matched                           |GNU or New (AT&T) `awk`
tarcat          |Print contents of `tar` archive file(s)                       |*
tarls           |List files within `tar` archive file(s)                       |*
unittest        |Wrapper around Python's `unittest` module                     |`python3`, GNU or New (AT&T) `awk`
untar           |Wrapper around `tar` for easier decompression                 |*
vimsplit        |Open two files in split windows                               |`nvim`
whichcat        |Print all lines from a program
whiched         |Open a program with your editor
whichhead       |Print the first 10 lines from a program                       |`bash`
whichvi         |Open a program with your visual editor
whisper         |Wrapper around `espeak` to mirror `say` in macOS              |`espeak`
wttr            |Wrapper around `wttr` to fix double-wide runes for some fonts |`wego`
zipls           |List files within `zip` archive file(s)                       |`zipinfo`


## Emulator Scripts

Executable       |Description                                            |Extra Dependencies
:----------------|:------------------------------------------------------|:-----------------
android-emulator |Start an Android emulator session                      |`adb`, `emulator`
qemu-test        |Check if hardware and OS are capable of virtualization |


## Docker Scripts

The following all depend on `docker`.

Executable                |Description                                                 |Extra Dependencies
:-------------------------|:-----------------------------------------------------------|:-----------------
docker-clean              |Stop all containers, remove all images, and clear the cache |
docker-get-all            |List all Docker containers' IDs                             |
docker-get-all-containers |List all Docker containers' (without service tasks) IDs     |
docker-get-all-services   |List all Docker services' IDs                               |
docker-get-exited         |List all exited Docker containers' IDs                      |
docker-restart            |Restart all exited Docker containers                        |
docker-up                 |Start a Docker container using `./docker-compose.yml`       |`docker-compose`


## Pulseaudio Scripts

The following all depend on `pactl`.

Executable            |Description                                          |Extra Dependencies
:---------------------|:----------------------------------------------------|:-----------------
pactl-get-running-sink|Get the currently running Pulseaudio sink ID         |
pactl-mute            |Toggle mute on the currently running Pulseaudio sink |
pactl-volume-down     |Reduce volume (default: 10%)                         |
pactl-volume-printf   |Print the currently running Pulseaudio sink volume   |
pactl-volume-up       |Increase volume (default: 10%)                       |


## VPN Scripts

Executable|Description                                               |Extra Dependencies
:---------|:---------------------------------------------------------|:-----------------
vpn-off   |Stop all OpenVPN connections                              |`killall`
vpn-on    |Start an OpenVPN connection using `$MYUTILS_OPENVPN_CONF` |`openvpn`
wg-off    |Stop the `wg0` Wireguard connection                       |`wg`, `wg-quick`
wg-on     |Start the `wg0` Wireguard connection                      |`wg`, `wg-quick`
wg-status |Print current Wireguard connection status                 |`wg`
wg-test   |Check if Wireguard connection is on and working           |`wg`


## Notes

\* *While you **technically** won't run into an error, these scripts **do**
expect `tar` to support Zstandard, which isn't necessarily POSIX standard.*

*All* scripts support `-h` and `--help` for printing built-in documentation.

*Almost all* scripts do nothing if no input arguments are given. (The
exceptions are `whisper` and `wttr`.)
*Almost all* scripts do nothing if no input arguments are given.


## Development

These being re-used scripts, there's been a great deal of feature creep,
bikeshedding, and over-engineering. That is to say, there's a lot of
uncertainty as to how *reliable* these scripts are. To mitigate these concerns,
`shellcheck` is a development dependency. A test suite is in the making, and
hopefully new entrants to this repository will come with tests.
These scripts are an unusual collection. Some I wrote from scratch, others are
owed to the unknown authors that posted their scripts to the /usr/local/bin
folder on a multi-user system.

There's been a great deal of feature creep, bikeshedding, and over-engineering.

Everything is always in alpha-mode. With that said, you can rely on `SCRIPT -v`
to ensure that there hasn't been a breaking change.


## License

If you really want to use anything in this repository-and I need to stress
*if you really want to*-just go right ahead. I'm licensing everything under
GPL because I'd appreciate you letting me know I messed something up. But you
*really* shouldn't try using anything here in production...
Go ahead.

I'm licensing everything under GPL because I'd appreciate you letting me know I
messed something up. But I'm not going to call the license police on you.


A archives/Makefile => archives/Makefile +39 -0
@@ 0,0 1,39 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 epub $(BIN_DIR)/epub
	install -m755 mktar $(BIN_DIR)/mktar
	install -m755 rmtar $(BIN_DIR)/rmtar
	install -m755 rmzip $(BIN_DIR)/rmzip
	install -m755 tarcat $(BIN_DIR)/tarcat
	install -m755 tarls $(BIN_DIR)/tarls
	install -m755 untar $(BIN_DIR)/untar
	install -m755 zipls $(BIN_DIR)/zipls

	install -m755 completion.bash $(COMP_DIR)/myutils_archives.bash

uninstall:
	rm $(BIN_DIR)/epub
	rm $(BIN_DIR)/mktar
	rm $(BIN_DIR)/rmtar
	rm $(BIN_DIR)/rmzip
	rm $(BIN_DIR)/tarcat
	rm $(BIN_DIR)/tarls
	rm $(BIN_DIR)/untar
	rm $(BIN_DIR)/zipls

	rm $(COMP_DIR)/myutils_archives.bash

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh
	sh test_init.sh
	sh test_mktar_tarcat.sh
	sh test_untar.sh

clean:
	rm -rf test/


A archives/README.md => archives/README.md +30 -0
@@ 0,0 1,30 @@
# archives utilities

Tools for creating, parsing, and scripting archive files.


## Specification

*While you **technically** won't run into an error, these scripts **do**
expect `tar` to support Zstandard, which isn't necessarily POSIX standard.*

Executable      |Description                                                   |Extra Dependencies
:---------------|:-------------------------------------------------------------|:------------------------------------------
epub            |Dumps HTML from an 'epub' e-book archive                      |`bash`, `zipinfo`, `unzip`, `w3m`
mktar           |Wrapper around `tar` for easier compression                   |`bash`
rmtar           |Delete 'tar' archive files                                    |
rmzip           |Delete 'zip' archive files                                    |
tarcat          |Print contents of `tar` archive file(s)                       |
tarls           |List files within `tar` archive file(s)                       |
untar           |Wrapper around `tar` for easier decompression                 |
zipls           |List files within `zip` archive file(s)                       |`zipinfo`

*All* scripts support `-h` and `--help` for printing built-in documentation.

*All* scripts do nothing if no input arguments are given.


## To-Do

 + add support for `rar`, `7z` archives


R bash-completion/mybashcompletion.bash => archives/completion.bash +7 -19
@@ 1,47 1,35 @@
#!/bin/bash
# provides completion in `bash` shells

# epub
# Function tries to find a target archive in arguments already specified, and
# then tries to list the filenames stored inside the archive
# try to find a target archive in arguments already specified
# if successful, complete with filenames present in that archive
# else, complete with filenames
_epub_completion() {
  # set fallback completion as default (filenames) with 'complete -o default'
  COMPREPLY=()
  # search for a filename in arguments, skipping the first (executable name)
  for arg in "${COMP_WORDS[@]:1}"; do
    if [[ -f "$arg" ]]; then
      # on finding a filename, try to complete with archive entries
      local list=( $(epub --list "$arg" | sort) )
      if [[ "${#list[@]}" -ge 1 ]]; then
        COMPREPLY=( $(compgen -W "${list[*]}" -- "${COMP_WORDS[$COMP_CWORD]}") )
      else
        # if not an archive, or an archive with no entries, halt completion
        compopt +o default
      fi
      break
    fi
  done
}
# Complete with function, and fallback to filenames
complete -o default -F _epub_completion epub

# rmzip, zipls
# Complete with filenames matching pattern '*.@(zip|cbr|epub)', and fallback to
# filenames
# complete with filenames like '*.@(zip|cbr|epub)'
complete -o default -f -X '!*.@(zip|cbr|epub)' rmzip
complete -o default -f -X '!*.@(zip|cbr|epub)' zipls

# rmtar, tarcat, tarls, untar
# Complete with filenames matching pattern
# '*.@(tar|tar.@(gz|xz|zst|bz2)|tar.@(gz|xz|zst|bz2).gpg)', and fallback to
# filenames
# complete with filenames like '*.@(tar|tar.@(gz|xz|zst|bz2)|tar.@(gz|xz|zst|bz2).gpg)'
complete -o default -f -X '!*.@(tar|tar.@(gz|xz|zst|bz2)|tar.@(gz|xz|zst|bz2).gpg)' rmtar
complete -o default -f -X '!*.@(tar|tar.@(gz|xz|zst|bz2)|tar.@(gz|xz|zst|bz2).gpg)' tarcat
complete -o default -f -X '!*.@(tar|tar.@(gz|xz|zst|bz2)|tar.@(gz|xz|zst|bz2).gpg)' tarls
complete -o default -f -X '!*.@(tar|tar.@(gz|xz|zst|bz2)|tar.@(gz|xz|zst|bz2).gpg)' untar

# whichcat, whiched. whichhead, whichvi
# Complete with program names
complete -c whichcat
complete -c whichhead
complete -c whiched
complete -c whichvi


R src/epub => archives/epub +0 -0
R src/mktar => archives/mktar +0 -0
R src/rmtar => archives/rmtar +0 -0
R src/rmzip => archives/rmzip +0 -0
R src/tarcat => archives/tarcat +0 -0
R src/tarls => archives/tarls +0 -0
A archives/test_init.sh => archives/test_init.sh +18 -0
@@ 0,0 1,18 @@
#!/bin/sh

# create and move into temp directory
mkdir test/
cd test/

# compression target
printf "[1]\n[2]\n[3]\n\n" > compression_target.txt

# decompression targets
printf "(a)\n(b)\n(c)\n\n" > decompression_result.txt
tar -cf decompression_target.tar decompression_result.txt
tar -czf decompression_target.tar.gz decompression_result.txt
tar -cJf decompression_target.tar.xz decompression_result.txt
tar --zstd -cf decompression_target.tar.zst decompression_result.txt
tar -cjf decompression_target.tar.bz2 decompression_result.txt
mv decompression_result.txt decompression_target.txt


R tests/compression_test.sh => archives/test_mktar_tarcat.sh +13 -49
@@ 1,10 1,12 @@
#!/bin/sh
# tests mktar and tarcat

# mktar and tarcat

cd tests/static
# move to temp directory
cd test

test_compression() {

  #set internal variables based on selected compression
  case "$1" in
    NONE)
      arg_compression="none"


@@ 32,24 34,26 @@ test_compression() {
      ;;
  esac

  #basic compression
  mktar compression_target.txt --compress="$arg_compression"
  tarcat "$fn_compressed" > compression_result.txt
  # try basic compression
  ../mktar compression_target.txt --compress="$arg_compression"
  ../tarcat "$fn_compressed" > compression_result.txt
  if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
    printf "Failure in compression tests: basic compression: '%s'\n" "$1"
    exit 1
  fi

  # clean up
  rm -f compression_result.txt "$fn_compressed"

  #implicit compression
  mktar compression_target.txt -n "$fn_compressed"
  tarcat "$fn_compressed" > compression_result.txt
  # try implicit compression
  ../mktar compression_target.txt -n "$fn_compressed"
  ../tarcat "$fn_compressed" > compression_result.txt
  if ! cmp compression_result.txt compression_target.txt >/dev/null 2>&1; then
    printf "Failure in compression tests: implicit compression: '%s'\n" "$1"
    exit 1
  fi

  # clean up
  rm -f compression_result.txt "$fn_compressed"
}



@@ 59,43 63,3 @@ test_compression XZ
test_compression ZSTD
test_compression BZIP2

# untar

test_decompression() {
  case "$1" in
    NONE)
      fn_compressed="decompression_target.tar"
      ;;
    GZIP)
      fn_compressed="decompression_target.tar.gz"
      ;;
    XZ)
      fn_compressed="decompression_target.tar.xz"
      ;;
    ZSTD)
      fn_compressed="decompression_target.tar.zst"
      ;;
    BZIP2)
      fn_compressed="decompression_target.tar.bz2"
      ;;
    *)
      printf "Failure in compression tests: not a valid scheme: '%s'\n" "$1"
      exit 1
      ;;
  esac

  untar "$fn_compressed"
  if ! cmp decompression_result.txt decompression_target.txt >/dev/null 2>&1; then
    printf "Failure in decompression tests: '%s'\n" "$1"
    exit 1
  fi

  rm -f decompression_result.txt
}

test_decompression NONE
test_decompression GZIP
test_decompression XZ
test_decompression ZSTD
test_decompression BZIP2


A archives/test_untar.sh => archives/test_untar.sh +48 -0
@@ 0,0 1,48 @@
#!/bin/sh
# tests untar

# move to temp directory
cd test

test_decompression() {

  #set internal variables based on selected compression
  case "$1" in
    NONE)
      fn_compressed="decompression_target.tar"
      ;;
    GZIP)
      fn_compressed="decompression_target.tar.gz"
      ;;
    XZ)
      fn_compressed="decompression_target.tar.xz"
      ;;
    ZSTD)
      fn_compressed="decompression_target.tar.zst"
      ;;
    BZIP2)
      fn_compressed="decompression_target.tar.bz2"
      ;;
    *)
      printf "Failure in compression tests: not a valid scheme: '%s'\n" "$1"
      exit 1
      ;;
  esac

  # try decompression
  ../untar "$fn_compressed"
  if ! cmp decompression_result.txt decompression_target.txt >/dev/null 2>&1; then
    printf "Failure in decompression tests: '%s'\n" "$1"
    exit 1
  fi

  # clean up
  rm -f decompression_result.txt
}

test_decompression NONE
test_decompression GZIP
test_decompression XZ
test_decompression ZSTD
test_decompression BZIP2


R src/untar => archives/untar +0 -0
R src/zipls => archives/zipls +0 -0
A containers/Makefile => containers/Makefile +35 -0
@@ 0,0 1,35 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 docker-clean $(BIN_DIR)/docker-clean
	install -m755 docker-get-all $(BIN_DIR)/docker-get-all
	install -m755 docker-get-all-containers $(BIN_DIR)/docker-get-all-containers
	install -m755 docker-get-all-services $(BIN_DIR)/docker-get-all-services
	install -m755 docker-get-exited $(BIN_DIR)/docker-get-exited
	install -m755 docker-restart $(BIN_DIR)/docker-restart
	install -m755 docker-up $(BIN_DIR)/docker-up
	install -m755 swarm-test $(BIN_DIR)/swarm-test

uninstall:
	rm $(BIN_DIR)/docker-clean
	rm $(BIN_DIR)/docker-get-all
	rm $(BIN_DIR)/docker-get-all-containers
	rm $(BIN_DIR)/docker-get-all-services
	rm $(BIN_DIR)/docker-get-exited
	rm $(BIN_DIR)/docker-restart
	rm $(BIN_DIR)/docker-up
	rm $(BIN_DIR)/swarm-test

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh
	sh test_init.sh
	sh test_swarm-test.sh

clean:
	rm -rf test/



A containers/README.md => containers/README.md +28 -0
@@ 0,0 1,28 @@
# containers utilities

Tools for managing, scripting, and automating containers.


## Specification

All are dependent on `docker`.

Executable                |Description                                                 |Extra Dependencies
:-------------------------|:-----------------------------------------------------------|:-----------------
docker-clean              |Stop all containers, remove all images, and clear the cache |
docker-get-all            |List all Docker containers' and services' IDs               |
docker-get-all-containers |List all Docker containers' IDs                             |
docker-get-all-services   |List all Docker services' IDs                               |
docker-get-exited         |List all exited Docker containers' IDs                      |
docker-restart            |Restart all exited Docker containers                        |
docker-up                 |Start a Docker container using `./docker-compose.yml`       |`docker-compose`
swarm-test                |Check if system is a swarm manager or node                  |

*All* scripts support `-h` and `--help` for printing built-in documentation.


## To-Do

 + make the calls to `docker` interchangable with e.g. `nerdctl` (see [here](https://github.com/containerd/nerdctl))
 + gate Docker swarm functionality behind `swarm-test` and drop split scripts


R src/docker-clean => containers/docker-clean +0 -0
R src/docker-get-all => containers/docker-get-all +0 -0
R src/docker-get-all-containers => containers/docker-get-all-containers +0 -0
R src/docker-get-all-services => containers/docker-get-all-services +0 -0
R src/docker-get-exited => containers/docker-get-exited +0 -0
R src/docker-restart => containers/docker-restart +0 -0
R src/docker-up => containers/docker-up +0 -0
A containers/swarm-test => containers/swarm-test +23 -0
@@ 0,0 1,23 @@
#!/bin/sh

name="swarm-test"
version="1.0"
help_message=$(/usr/bin/cat <<-EOF
	Check if system is a Docker swarm manager or node
	Usage: swarm-test
	Options:
	 -h, --help     print this message and exit
	 -v, --version  print version number and exit
EOF
)

. /usr/local/lib/myminiparse.sh

if ! docker service ls >/dev/null 2>&1; then
  if [ "$quiet" -eq 0 ]; then
    (>&2 /usr/bin/printf "%s: not a swarm manager or node\n" "$name")
  fi
  exit 1
fi
exit 0


A containers/test_init.sh => containers/test_init.sh +6 -0
@@ 0,0 1,6 @@
#!/bin/sh

# create and move into temp directory
mkdir test
cd test


A containers/test_swarm-test.sh => containers/test_swarm-test.sh +16 -0
@@ 0,0 1,16 @@
#!/bin/sh
# tests swarm-test

# move to temp directory
cd test

test_exit_code() {
  $1 >/dev/null 2>&1
  if [ $? -ne $2 ]; then
    printf "Failure in swarm-test tests: wrong exit code ('$1' returned '$?', should be '$2')\n"
    exit 1
  fi
}
test_exit_code "../swarm-test -v" "0"
test_exit_code "../swarm-test -h" "0"


A core/Makefile => core/Makefile +70 -0
@@ 0,0 1,70 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 ctdir $(BIN_DIR)/ctdir
	install -m755 debom $(BIN_DIR)/debom
	install -m755 enumerate $(BIN_DIR)/enumerate
	install -m755 git-set-remotes $(BIN_DIR)/git-set-remotes
	install -m755 mkbak $(BIN_DIR)/mkbak
	install -m755 rand $(BIN_DIR)/rand
	install -m755 rebom $(BIN_DIR)/rebom
	install -m755 rmold $(BIN_DIR)/rmold
	install -m755 start-at $(BIN_DIR)/start-at
	install -m755 stop-at $(BIN_DIR)/stop-at
	install -m755 unittest $(BIN_DIR)/unittest
	install -m755 vimsplit $(BIN_DIR)/vimsplit
	install -m755 whichcat $(BIN_DIR)/whichcat
	install -m755 whiched $(BIN_DIR)/whiched
	install -m755 whichhead $(BIN_DIR)/whichhead
	install -m755 whichvi $(BIN_DIR)/whichvi
	install -m755 wttr $(BIN_DIR)/wttr

	install -m755 mylib.bash $(LIB_DIR)/mylib.bash
	install -m755 myminiparse.sh $(LIB_DIR)/myminiparse.sh
	install -m755 myparse.bash $(LIB_DIR)/myparse.bash
	install -m755 unittest-color.awk $(LIB_DIR)/unittest-color.awk

	install -m755 completion.bash $(COMP_DIR)/myutils_core.bash

uninstall:
	rm $(BIN_DIR)/ctdir
	rm $(BIN_DIR)/debom
	rm $(BIN_DIR)/enumerate
	rm $(BIN_DIR)/git-set-remotes
	rm $(BIN_DIR)/mkbak
	rm $(BIN_DIR)/rand
	rm $(BIN_DIR)/rebom
	rm $(BIN_DIR)/rmold
	rm $(BIN_DIR)/start-at
	rm $(BIN_DIR)/stop-at
	rm $(BIN_DIR)/unittest
	rm $(BIN_DIR)/vimsplit
	rm $(BIN_DIR)/whichcat
	rm $(BIN_DIR)/whiched
	rm $(BIN_DIR)/whichhead
	rm $(BIN_DIR)/whichvi
	rm $(BIN_DIR)/wttr

	rm $(LIB_DIR)/mylib.bash
	rm $(LIB_DIR)/myminiparse.sh
	rm $(LIB_DIR)/myparse.bash
	rm $(LIB_DIR)/unittest-color.awk

	rm $(COMP_DIR)/myutils_core.bash

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh
	sh test_init.sh
	sh test_debom_rebom.sh
	sh test_ctdir.sh
	sh test_whichcat_whichhead.sh
	sh test_whiched_whichvi.sh

clean:
	rm -rf test/



A core/completion.bash => core/completion.bash +10 -0
@@ 0,0 1,10 @@
#!/bin/bash
# provides completion in `bash` shells

# whichcat, whiched. whichhead, whichvi
# try to complete with program names
complete -c whichcat
complete -c whichhead
complete -c whiched
complete -c whichvi


R src/ctdir => core/ctdir +0 -0
R src/debom => core/debom +0 -0
R src/enumerate => core/enumerate +0 -0
R src/git-set-remotes => core/git-set-remotes +0 -0
R src/mkbak => core/mkbak +0 -0
R src/mylib.bash => core/mylib.bash +0 -0
R src/myminiparse.sh => core/myminiparse.sh +0 -0
R src/myparse.bash => core/myparse.bash +0 -0
R src/rand => core/rand +0 -0
R src/rebom => core/rebom +0 -0
R src/rmold => core/rmold +0 -0
R src/start-at => core/start-at +0 -0
R src/stop-at => core/stop-at +0 -0
A core/test_ctdir.sh => core/test_ctdir.sh +35 -0
@@ 0,0 1,35 @@
#!/bin/sh
# tests ctdir

# move to temp directory
cd test

test_exit_code() {
  $1 >/dev/null 2>&1
  if [ $? -ne $2 ]; then
    printf "Failure in ctdir tests: wrong exit code ('$1' returned '$?', should be '$2')\n"
    exit 1
  fi
}
test_exit_code "../ctdir -v" "0"
test_exit_code "../ctdir -h" "0"
test_exit_code "../ctdir" "1"
test_exit_code "../ctdir non-existant-directory" "1"
test_exit_code "../ctdir ." "0"
test_exit_code "../ctdir . non-existant-directory" "1"
test_exit_code "../ctdir non-existant-directory ." "1"
test_exit_code "../ctdir . ." "0"

count=0
for n in $(../ctdir ./ctdir ./ctdir); do
  count=$(($count+1))
  if [ "$n" -ne 10 ]; then
    printf "Failure in ctdir tests: wrong return value\n"
    exit 1
  fi
done
if [ $count -ne 2 ]; then
  printf "Failure in ctdir tests: wrong number of return values\n"
  exit 1
fi


A core/test_debom_rebom.sh => core/test_debom_rebom.sh +36 -0
@@ 0,0 1,36 @@
#!/bin/sh
# tests demon and rebom

# move to temp directory
cd test

test_exit_code() {
  $1 >/dev/null 2>&1
  if [ $? -ne $2 ]; then
    printf "Failure in BOM tests: wrong exit code ('$1' returned '$?', should be '$2')\n"
    exit 1
  fi
}
test_exit_code "../debom -V" "0"
test_exit_code "../debom -h" "0"
test_exit_code "../debom" "1"
test_exit_code "../debom non-existant-file" "1"
test_exit_code "../rebom -v" "0"
test_exit_code "../rebom -h" "0"
test_exit_code "../rebom" "1"
test_exit_code "../rebom non-existant-file" "1"

# try de-BOM-ing a file
../debom -d debom_target.txt > debom_result.txt
if ! cmp rebom_target.txt debom_result.txt >/dev/null 2>&1; then
  printf "Failure in BOM tests: de-BOM-ed file is corrupt\n"
  exit 1
fi

# try re-BOM-ing a file
../rebom rebom_target.txt > rebom_result.txt
if ! cmp debom_target.txt rebom_result.txt >/dev/null 2>&1; then
  printf "Failure in BOM tests: re-BOM-ed file is corrupt\n"
  exit 1
fi


A core/test_init.sh => core/test_init.sh +17 -0
@@ 0,0 1,17 @@
#!/bin/sh

# create and move into temp directory
mkdir test
cd test

# debom target
printf "\xEF\xBB\xBFfoo bar\n" > debom_target.txt

# rebom target
printf "foo bar\n" > rebom_target.txt

# ctdir targets
mkdir ctdir
touch ctdir/{a,b,c,d,e}.txt
touch ctdir/.{f,g,h,i,j}.txt


A core/test_whichcat_whichhead.sh => core/test_whichcat_whichhead.sh +34 -0
@@ 0,0 1,34 @@
#!/bin/sh
# tests whichcat and whichhead

# move to temp directory
cd test

test_exit_code() {
  $1 >/dev/null 2>&1
  if [ $? -ne $2 ]; then
    printf "Failure in whichcat tests: wrong exit code ('$1' returned '$?', should be '$2')\n"
    exit 1
  fi
}
test_exit_code "../whichcat -v" "0"
test_exit_code "../whichcat -h" "0"
test_exit_code "../whichcat" "0"
test_exit_code "../whichcat non-existant-binary" "1"
test_exit_code "../whichhead -v" "0"
test_exit_code "../whichhead -h" "0"
test_exit_code "../whichhead" "0"
test_exit_code "../whichhead non-existant-binary" "1"

should_be="$(wc -l ../whichcat | cut --delimiter=' ' --fields=1)"
if [ "$(cd .. && ./whichcat whichcat | wc -l)" -ne "$should_be" ]; then
  printf "Failure in whichcat tests: wrong file returned\n"
  exit 1
fi

should_be="$((should_be * 2))"
if [ "$(cd .. && ./whichcat whichcat whichcat | wc -l)" -ne "$should_be" ]; then
  printf "Failure in whichcat tests: wrong files returned\n"
  exit 1
fi


A core/test_whiched_whichvi.sh => core/test_whiched_whichvi.sh +33 -0
@@ 0,0 1,33 @@
#!/bin/sh
# tests whiched and whichvi

# move to temp directory
cd test

test_exit_code() {
  $1 >/dev/null 2>&1
  if [ $? -ne $2 ]; then
    printf "Failure in whiched tests: wrong exit code ('$1' returned '$?', should be '$2')\n"
    exit 1
  fi
}
test_exit_code "../whiched -v" "0"
test_exit_code "../whiched -h" "0"
test_exit_code "../whiched" "0"
test_exit_code "../whiched non-existant-binary" "1"

EDITOR=true
test_exit_code "../whiched sh" "0"
EDITOR=false
test_exit_code "../whiched sh" "1"

test_exit_code "../whichvi -v" "0"
test_exit_code "../whichvi -h" "0"
test_exit_code "../whichvi" "0"
test_exit_code "../whichvi non-existant-binary" "1"

VISUAL=true
test_exit_code "../whichvi sh" "0"
VISUAL=false
test_exit_code "../whichvi sh" "1"


R src/unittest => core/unittest +0 -0
R src/unittest-color.awk => core/unittest-color.awk +0 -0
R src/vimsplit => core/vimsplit +0 -0
R src/whichcat => core/whichcat +0 -0
R src/whiched => core/whiched +11 -4
@@ 1,7 1,7 @@
#!/bin/sh

name="whiched"
version="1.0"
version="1.1"
help_message=$(/usr/bin/cat <<-EOF
	Open a program with your editor
	Usage: whiched PROGRAM [OPTIONS]


@@ 14,7 14,8 @@ EOF

. /usr/local/lib/myminiparse.sh

# open first non-option argument in editor, then exit
# NOTE: intentionally does not mirror `whichcat`/`whichhead`; doesn't make
# sense to handle multiple files
for arg; do
  case "$arg" in
  -q|--quiet)


@@ 26,11 27,17 @@ for arg; do
    target=$(command -v "$arg")
    if [ -z "$target" ]; then
      if [ "$quiet" -eq 0 ]; then
        (>&2 /usr/bin/printf "%s: No such directory '%s'\n" "$name" "$target")
        (>&2 /usr/bin/printf "%s: No such program '%s'\n" "$name" "$arg")
      fi
      exit 1
    else
      my_editor=${EDITOR:=/usr/bin/ed}
      if ! command -v "$my_editor" >/dev/null 2>&1; then
        if [ "$quiet" -eq 0 ]; then
          (>&2 /usr/bin/printf "%s: cannot call \$EDITOR '%s', falling back to '/usr/bin/ed'\n" "$name" "$my_editor")
        fi
        my_editor=/usr/bin/ed
      fi
      $my_editor "$target"
      exit $?
    fi


@@ 42,5 49,5 @@ done
if [ "$quiet" -eq 0 ]; then
  (>&2 /usr/bin/printf "Usage: whiched PROGRAM [OPTIONS]\n")
fi
exit 1
exit 0


R src/whichhead => core/whichhead +0 -0
R src/whichvi => core/whichvi +12 -5
@@ 1,7 1,7 @@
#!/bin/sh

name="whichvi"
version="1.0"
version="1.1"
help_message=$(/usr/bin/cat <<-EOF
	Open a program with your visual editor
	Usage: whichvi PROGRAM [OPTIONS]


@@ 14,7 14,8 @@ EOF

. /usr/local/lib/myminiparse.sh

# open first non-option argument in editor, then exit
# NOTE: intentionally does not mirror `whichcat`/`whichhead`; doesn't make
# sense to handle multiple files
for arg; do
  case "$arg" in
  -q|--quiet)


@@ 26,11 27,17 @@ for arg; do
    target=$(command -v "$arg")
    if [ -z "$target" ]; then
      if [ "$quiet" -eq 0 ]; then
        (>&2 /usr/bin/printf "%s: No such directory '%s'\n" "$name" "$target")
        (>&2 /usr/bin/printf "%s: No such program '%s'\n" "$name" "$arg")
      fi
      exit 1
    else
      my_visual=${VISUAL:=/usr/bin/ed}
      my_visual=${VISUAL:=/usr/bin/vi}
      if ! command -v "$my_visual" >/dev/null 2>&1; then
        if [ "$quiet" -eq 0 ]; then
          (>&2 /usr/bin/printf "%s: cannot call \$VISUAL '%s', falling back to '/usr/bin/vi'\n" "$name" "$my_visual")
        fi
        my_visual=/usr/bin/vi
      fi
      $my_visual "$target"
      exit $?
    fi


@@ 42,5 49,5 @@ done
if [ "$quiet" -eq 0 ]; then
  (>&2 /usr/bin/printf "Usage: whichvi PROGRAM [OPTIONS]\n")
fi
exit 1
exit 0


R src/wttr => core/wttr +0 -0
A display/Makefile => display/Makefile +21 -0
@@ 0,0 1,21 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 check-x $(BIN_DIR)/check-x
	install -m755 resetx $(BIN_DIR)/resetx

uninstall:
	rm $(BIN_DIR)/check-x
	rm $(BIN_DIR)/resetx

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh
	sh test_check-x.sh

clean:



A display/README.md => display/README.md +22 -0
@@ 0,0 1,22 @@
# display utilities

Tools for managing and scripting with displays and window servers.


## Specification

Executable|Description                          |Extra Dependencies
:---------|:------------------------------------|:-----------------
check-x   |Check if an X11 server is running    |
resetx    |Reset X server monitor configuration |`xrandr`

*All* scripts support `-h` and `--help` for printing built-in documentation.


## To-Do

 + define better naming scheme
 + make compatible with `sway`
 + add `i3`/`sway` bar script



R src/check-x => display/check-x +0 -0
R src/resetx => display/resetx +0 -0
A display/test_check-x.sh => display/test_check-x.sh +13 -0
@@ 0,0 1,13 @@
#!/bin/sh
# tests check-x

test_exit_code() {
  $1 >/dev/null 2>&1
  if [ $? -ne $2 ]; then
    printf "Failure in check-x tests: wrong exit code ('$1' returned '$?', should be '$2')\n"
    exit 1
  fi
}
test_exit_code "check-x -v" "0"
test_exit_code "check-x -h" "0"


A emulation/Makefile => emulation/Makefile +21 -0
@@ 0,0 1,21 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 android-emulator $(BIN_DIR)/android-emulator
	install -m755 qemu-test $(BIN_DIR)/qemu-test

uninstall:
	rm $(BIN_DIR)/android-emulator
	rm $(BIN_DIR)/qemu-test

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh
	sh test_qemu-test.sh

clean:



A emulation/README.md => emulation/README.md +20 -0
@@ 0,0 1,20 @@
# containers utilities

Tools for managing emulators and related software.


## Specification

Executable       |Description                                            |Extra Dependencies
:----------------|:------------------------------------------------------|:-----------------
android-emulator |Start an Android emulator session                      |`adb`, `emulator`
qemu-test        |Check if hardware and OS are capable of virtualization |

*All* scripts support `-h` and `--help` for printing built-in documentation.


## To-Do

 + add scripts for managing game emulators (i.e. `desmume`, `mgba`, `mgba-qt`)



R src/android-emulator => emulation/android-emulator +0 -0
R src/qemu-test => emulation/qemu-test +0 -0
A emulation/test_qemu-test.sh => emulation/test_qemu-test.sh +13 -0
@@ 0,0 1,13 @@
#!/bin/sh
# tests qemu-test

test_exit_code() {
  $1 >/dev/null 2>&1
  if [ $? -ne $2 ]; then
    printf "Failure in qemu-test tests: wrong exit code ('$1' returned '$?', should be '$2')\n"
    exit 1
  fi
}
test_exit_code "qemu-test -v" "0"
test_exit_code "qemu-test -h" "0"


A games/Makefile => games/Makefile +19 -0
@@ 0,0 1,19 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 whisper $(BIN_DIR)/whisper

uninstall:
	rm $(BIN_DIR)/whisper

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh

clean:
	rm -rf test/



A games/README.md => games/README.md +16 -0
@@ 0,0 1,16 @@
# games utilities

Fun or funny tools. Not necessarily games.


## Specification

Executable|Description                                      |Extra Dependencies
:---------|:------------------------------------------------|:-----------------
whisper   |Wrapper around `espeak` to mirror `say` in macOS |`espeak`

*All* scripts support `-h` and `--help` for printing built-in documentation.


## To-Do


R src/whisper => games/whisper +0 -0
A network/Makefile => network/Makefile +33 -0
@@ 0,0 1,33 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 fw-status $(BIN_DIR)/fw-status
	install -m755 pingable $(BIN_DIR)/pingable
	install -m755 vpn-off $(BIN_DIR)/vpn-off
	install -m755 vpn-on $(BIN_DIR)/vpn-on
	install -m755 wg-off $(BIN_DIR)/wg-off
	install -m755 wg-on $(BIN_DIR)/wg-on
	install -m755 wg-status $(BIN_DIR)/wg-status
	install -m755 wg-test $(BIN_DIR)/wg-test

uninstall:
	rm $(BIN_DIR)/fw-status
	rm $(BIN_DIR)/pingable
	rm $(BIN_DIR)/vpn-off
	rm $(BIN_DIR)/vpn-on
	rm $(BIN_DIR)/wg-off
	rm $(BIN_DIR)/wg-on
	rm $(BIN_DIR)/wg-status
	rm $(BIN_DIR)/wg-test

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh

clean:
	rm -rf test/



A network/README.md => network/README.md +31 -0
@@ 0,0 1,31 @@
# network utilities

Tools for managing real and virtual networks.


## Specification

Executable|Description                                               |Extra Dependencies
:---------|:---------------------------------------------------------|:-----------------
fw-status |Print current firewall status                             |`ufw`
pingable  |Check if an address/name is ping-able                     |`ping`
vpn-off   |Stop all OpenVPN connections                              |`killall`
vpn-on    |Start an OpenVPN connection using `$MYUTILS_OPENVPN_CONF` |`openvpn`
wg-off    |Stop the `wg0` Wireguard connection                       |`wg`, `wg-quick`
wg-on     |Start the `wg0` Wireguard connection                      |`wg`, `wg-quick`
wg-status |Print current Wireguard connection status                 |`wg`
wg-test   |Check if Wireguard connection is on and working           |`wg`

*All* scripts support `-h` and `--help` for printing built-in documentation.


## To-Do

 + add support for variable `openvpn` configurations, `wg` interface names
 + script for listing, adding wi-fi connections
 + scripts for testing connections at each of the following levels:
   + DNS resolution
   + ping connection
   + HTTP GET connection
   + SSL/TLS certificate validation


R src/fw-status => network/fw-status +0 -0
R src/pingable => network/pingable +0 -0
R src/vpn-off => network/vpn-off +0 -0
R src/vpn-on => network/vpn-on +0 -0
R src/wg-off => network/wg-off +0 -0
R src/wg-on => network/wg-on +0 -0
R src/wg-status => network/wg-status +0 -0
R src/wg-test => network/wg-test +0 -0
A sound/Makefile => sound/Makefile +26 -0
@@ 0,0 1,26 @@
BIN_DIR?=/usr/local/bin
LIB_DIR?=/usr/local/lib
COMP_DIR?=/usr/local/etc/bash_completion.d

.PHONY: install uninstall test clean

install:
	install -m755 pactl-get-running-sink $(BIN_DIR)/pactl-get-running-sink
	install -m755 pactl-mute $(BIN_DIR)/pactl-mute
	install -m755 pactl-volume-down $(BIN_DIR)/pactl-volume-down
	install -m755 pactl-volume-printf $(BIN_DIR)/pactl-volume-printf
	install -m755 pactl-volume-up $(BIN_DIR)/pactl-volume-up

uninstall:
	rm $(BIN_DIR)/pactl-get-running-sink
	rm $(BIN_DIR)/pactl-mute
	rm $(BIN_DIR)/pactl-volume-down
	rm $(BIN_DIR)/pactl-volume-printf
	rm $(BIN_DIR)/pactl-volume-up

test: clean
	#shellcheck *.bash *.sh $(LIB_DIR)/mylib.bash $(LIB_DIR)/myparse.bash $(LIB_DIR)/myminiparse.sh

clean:



A sound/README.md => sound/README.md +23 -0
@@ 0,0 1,23 @@
# sound utilities

Tools for managing, scripting, and automating sound servers and audio sinks.


## Specification

All are dependent on `pactl`.

Executable            |Description                                          |Extra Dependencies
:---------------------|:----------------------------------------------------|:-----------------
pactl-get-running-sink|Get the currently running Pulseaudio sink ID         |
pactl-mute            |Toggle mute on the currently running Pulseaudio sink |
pactl-volume-down     |Reduce volume (default: 10%)                         |
pactl-volume-printf   |Print the currently running Pulseaudio sink volume   |
pactl-volume-up       |Increase volume (default: 10%)                       |

*All* scripts support `-h` and `--help` for printing built-in documentation.

## To-Do

 + make compatible with `amixer`, `pipewire`


R src/pactl-get-running-sink => sound/pactl-get-running-sink +0 -0
R src/pactl-mute => sound/pactl-mute +0 -0
R src/pactl-volume-down => sound/pactl-volume-down +0 -0
R src/pactl-volume-printf => sound/pactl-volume-printf +0 -0
R src/pactl-volume-up => sound/pactl-volume-up +0 -0
D tests/bom_test.sh => tests/bom_test.sh +0 -52
@@ 1,52 0,0 @@
#!/bin/sh

# debom

cd tests/static

# exit codes
if ! debom -V >/dev/null 2>&1; then
  printf "Wrong exit code on 'debom -V' - should be 0\n"
  exit 1
elif ! debom -h >/dev/null 2>&1; then
  printf "Wrong exit code on 'debom -h' - should be 0\n"
  exit 1
elif debom >/dev/null 2>&1; then
  printf "Wrong exit code on 'debom' - should be 1\n"
  exit 1
elif debom non-existant >/dev/null 2>&1; then
  printf "Wrong exit code on 'debom non-existant' should be 1\n"
  exit 1
fi

# de-BOM a file
debom -d debom_target.txt > debom_result.txt
if ! cmp rebom_target.txt debom_result.txt >/dev/null 2>&1; then
  printf "Failure in de-BOM test\n"
  exit 1
fi

# rebom

# exit codes
if ! rebom -v >/dev/null 2>&1; then
  printf "Wrong exit code on 'rebom -v' - should be 0\n"
  exit 1
elif ! rebom -h >/dev/null 2>&1; then
  printf "Wrong exit code on 'rebom -h' - should be 0\n"
  exit 1
elif rebom >/dev/null 2>&1; then
  printf "Wrong exit code on 'rebom' - should be 1\n"
  exit 1
elif rebom non-existant >/dev/null 2>&1; then
  printf "Wrong exit code on 'rebom non-existant' should be 1\n"
  exit 1
fi

# re-BOM a file
rebom rebom_target.txt > rebom_result.txt
if ! cmp debom_target.txt rebom_result.txt >/dev/null 2>&1; then
  printf "Failure in re-BOM test\n"
  exit 1
fi


D tests/ctdir_test.sh => tests/ctdir_test.sh +0 -36
@@ 1,36 0,0 @@
#!/bin/sh

# ctdir

# exit codes
if ! ctdir -v >/dev/null 2>&1; then
  printf "Wrong exit code on 'ctdir -v' - should be 0\n"
  exit 1
elif ! ctdir -h >/dev/null 2>&1; then
  printf "Wrong exit code on 'ctdir -h' - should be 0\n"
  exit 1
elif ctdir >/dev/null 2>&1; then
  printf "Wrong exit code on 'ctdir' - should be 1\n"
  exit 1
elif ctdir non-existant >/dev/null 2>&1; then
  printf "Wrong exit code on 'ctdir non-existant' should be 1\n"
  exit 1
elif ! ctdir . >/dev/null 2>&1; then
  printf "Wrong exit code on 'ctdir .' should be 0\n"
  exit 1
fi

# output
num=$(ctdir .)
if [ ! "$num" -eq "$num" ] 2>/dev/null; then
  printf "Did not return a number on 'ctdir .'\n"
  exit 1
fi

# behavior on multiple inputs
lines=$(ctdir . . | wc -l)
if [ "$lines" -ne 2 ] 2>/dev/null; then
  printf "Did not return a number for each input on 'ctdir . .'\n"
  exit 1
fi


D tests/init.sh => tests/init.sh +0 -22
@@ 1,22 0,0 @@
#!/bin/sh

mkdir tests/static

# compression target
printf "[1]\n[2]\n[3]\n\n" > tests/static/compression_target.txt

# debom target
printf "\xEF\xBB\xBFfoo bar\n" > tests/static/debom_target.txt

# rebom target
printf "foo bar\n" > tests/static/rebom_target.txt

# decompression targets
printf "(a)\n(b)\n(c)\n\n" > tests/static/decompression_result.txt
tar -C tests/static -cf tests/static/decompression_target.tar decompression_result.txt
tar -C tests/static -czf tests/static/decompression_target.tar.gz decompression_result.txt
tar -C tests/static -cJf tests/static/decompression_target.tar.xz decompression_result.txt
tar -C tests/static --zstd -cf tests/static/decompression_target.tar.zst decompression_result.txt
tar -C tests/static -cjf tests/static/decompression_target.tar.bz2 decompression_result.txt
mv tests/static/decompression_result.txt tests/static/decompression_target.txt


D tests/which_test.sh => tests/which_test.sh +0 -92
@@ 1,92 0,0 @@
#!/bin/sh

# whichcat

# exit codes
if ! whichcat -v >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichcat -v' - should be 0\n"
  exit 1
elif ! whichcat -h >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichcat -h' - should be 0\n"
  exit 1
elif ! whichcat >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichcat' - should be 0\n"
  exit 1
elif whichcat non-existant >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichcat non-existant' - should be 1\n"
  exit 1
elif ! whichcat whichcat >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichcat whichcat' - should be 0\n"
  exit 1
fi

# behavior on multiple inputs
lines_once=$(whichcat whichcat | wc -l)
lines_twice=$(whichcat whichcat whichcat | wc -l)
if [ "$lines_once" -ge "$lines_twice" ] 2>/dev/null; then
  printf "Did not print output for each input on 'whichcat whichcat whichcat'\n"
  exit 1
fi

# whichhead

# exit codes
if ! whichhead -V >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichhead -v' - should be 0\n"
  exit 1
elif ! whichhead -h >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichhead -V' - should be 0\n"
  exit 1
elif ! whichhead >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichhead' - should be 0\n"
  exit 1
elif whichhead non-existant >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichhead non-existant' - should be 1\n"
  exit 1
elif ! whichhead whichhead >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichhead whichhead' - should be 0\n"
  exit 1
fi

# behavior on multiple inputs
lines_once=$(whichhead whichhead | wc -l)
lines_twice=$(whichhead whichhead whichhead | wc -l)
if [ "$lines_once" -ge "$lines_twice" ] 2>/dev/null; then
  printf "Did not print output for each input on 'whichhead whichhead whichhead'\n"
  exit 1
fi

# whiched

# exit codes
if ! whiched -v >/dev/null 2>&1; then
  printf "Wrong exit code on 'whiched -v' - should be 0\n"
  exit 1
elif ! whiched -h >/dev/null 2>&1; then
  printf "Wrong exit code on 'whiched -V' - should be 0\n"
  exit 1
elif whiched >/dev/null 2>&1; then
  printf "Wrong exit code on 'whiched' - should be 1\n"
  exit 1
elif whiched non-existant >/dev/null 2>&1; then
  printf "Wrong exit code on 'whiched non-existant' - should be 1\n"
  exit 1
fi

# whichvi

# exit codes
if ! whichvi -v >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichvi -v' - should be 0\n"
  exit 1
elif ! whichvi -h >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichvi -V' - should be 0\n"
  exit 1
elif whichvi >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichvi' - should be 1\n"
  exit 1
elif whichvi non-existant >/dev/null 2>&1; then
  printf "Wrong exit code on 'whichvi non-existant' - should be 1\n"
  exit 1
fi