Skip to content

Instantly share code, notes, and snippets.

@l3laze
Created September 12, 2018 08:22
Show Gist options
  • Save l3laze/f89e99672875f4e40b0b200d8393cc4b to your computer and use it in GitHub Desktop.
Save l3laze/f89e99672875f4e40b0b200d8393cc4b to your computer and use it in GitHub Desktop.
Package-manager-like tool for commands, memba?
#!/usr/bin/env bash
#
# Memba - A "package manager" for global and local commands.
#
# Follows the suggested exit code range of 0 & 64-113 from http://www.tldp.org/LDP/abs/html/exitcodes.html
#
# | Exit Code | Meaning |
# | --- | --- |
# | 64 | Error -- no command |
# | 65 | Error -- unknown command |
# | 66 | Error -- no target pattern for remove/rm/- or remove-all/rma |
# | 67 | Error -- no command for add/+ |
# | 67 | Error -- command already exists |
set -e # Enable "exit on first error"
#--------------------------------------------
# Utility functions memba?
#
# Based on https://stackoverflow.com/a/3232082/7665043
confirm() {
# call with a prompt string or use a default
read -r -p "${1:-Are you sure? [y/N]} " response
case "$response" in
[yY][eE][sS]|[yY])
echo 0
;;
*)
echo 1
;;
esac
}
# Based on https://stackoverflow.com/a/3951175/7665043
function isNumber () {
case $1 in
''|*[!0-9]*) echo 1 ;;
*) echo 0 ;;
esac
}
function joinArray () {
echo "${@}"
}
# Based on https://stackoverflow.com/a/17841619/7665043
function joinBy {
local d=$1
shift
echo -n "$1"
shift
printf "%s" "${@/#/$d}"
}
# Based on https://stackoverflow.com/a/39463371/7665043
expand-q () {
for i; do
printf "%s " "${i@Q}"
done
echo
}
#--------------------------------------------
# Functions, memba?
#
function membaUsage () {
echo "Don't you memba...?"
}
function membaAdd () {
local membaConfig="$1"
local exists="false"
shift
[[ "$1" == "" ]] && echo "There must be a commands provided as a non-empty string provided for add/+." && membaUsage && exit 67
[[ $(grep -c "^$1$" "$membaConfig") != "0" ]] && exists="true"
[[ "$exists" == "true" ]] && echo "\"$1\" already exists, memba?" && exit 68
while [[ "$#" -gt 0 ]]; do
echo "${@}" >> "$membaConfig"
shift
done
}
function membaList () {
local membaConfig="$1"
shift
if [[ "$#" -ne 0 ]]; then
local pattern="$1"
grep "$pattern" "$membaConfig"
else
cat "$membaConfig"
fi
}
function membaListNumbered () {
membaList "$@" | nl -n ln -w 1 -s " "
}
function membaChoice () {
local membaConfig="$1"
local pattern
local choicesMemba
local choicesLen
local inp
local choiceMessage
local chosen
local membad
local target
shift
target=$(joinArray "${@}")
choicesMemba=$(membaListNumbered "$membaConfig" "$@")
choicesLen=$(echo "$choicesMemba" | tail -n 1 | awk '{ print $1 }')
[[ "$choicesLen" -eq 0 ]] && echo "There's no commands with \"$target\", memba?" && exit 0
membad=$(if [[ "$target" != "" ]]; then
printf "I memba %sx command" "$choicesLen"
[[ "$#" -gt 1 ]] && printf "s"
echo " with \"$target\"."
else
printf "I memba %sx command" "$choicesLen"
[[ "$#" -gt 1 ]] && printf "s"
echo "."
fi)
choiceMessage=$(echo -e "$membad\n--------\n$choicesMemba\n\n--------\nChoose a command by number or 0 to cancel, memba?\nChoice: ")
while [[ -z "$inp" || $(isNumber "$inp") -eq 1 || "$inp" -lt 0 || "$inp" -gt $choicesLen ]]; do
clear > "$(tty)"
[[ "$inp" != "" ]] && echo -e "$inp is not a choice, memba?\n"
read -r -p "$choiceMessage" inp
inp=$(echo "$inp" | tr -d '[:space:]')
done
if [[ "$inp" -ne 0 ]]; then
chosen=$(echo "$choicesMemba" | awk '$1 == inp { for(i=2;i<=NF;++i) print $i }' inp="$inp" | tr '\n' ' ')
else
chosen="cancel"
fi
if [[ "$chosen" != "cancel" ]]; then
$chosen || echo "That command is broken, memba?"
fi
}
function membaRemove () {
local membaConfig="$1"
local matches
local count=0
local target
local message
local newConfig
shift
target=$(joinArray "${@}")
[[ "$target" == "" ]] && echo "There must be a pattern provided as a non-empty string for remove-all/rma, memba?" && membaUsage && exit 66
matches=$(grep "$target" "$membaConfig")
count=$(grep -c "$target" "$membaConfig")
[[ "$count" -lt 1 ]] && echo "No, I don't memba \"$target\".." && exit 68
message=$(echo -e "Are you sure you want to remove all commands containing \"$target\"?\n${matches}\n[y/N], memba?:")
echo "I memba ""$count""x command"
[[ "$#" -gt 1 ]] && printf "s"
" with \"$target\"."
if [[ "$count" -ne 0 && $(confirm "$message") -eq 0 ]]; then
newConfig=$(awk '!/'"$target"'/ { print }' < "$membaConfig")
[[ "$newConfig" == "" ]] && printf "" > "$membaConfig" || echo "$newConfig" > "$membaConfig"
fi
}
#--------------------------------------------
# Parse args and run, memba!?
#
function runScript () {
local membaConfig="$HOME/.memba"
if [[ "$#" -eq 0 ]]; then
# Display usage..
echo "This needs a command, memba?"
membaUsage
exit 64
else
local option="$1"
shift
case $option in
"add" | "+" )
membaAdd "$membaConfig" "$@"
;;
"choice" | "ch" | "?" )
membaChoice "$membaConfig" "$@"
;;
"list" | "ls" | "." )
membaList "$membaConfig" "$@"
;;
"remove" | "rm" | "-" )
membaRemove "$membaConfig" "$@"
;;
* )
echo "Unknown command \"$option\", memba?"
membaUsage
exit 66
esac
fi
}
calledWith=$(expand-q $(ps -o args= $$ | awk '{ for(i=4;i<=NF;++i) print $i }' ))
echo "$calledWith"
runScript "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment