Last active
April 6, 2022 02:47
-
-
Save jaymecd/ca05ad4e36f8816cd0c868f53c96962e to your computer and use it in GitHub Desktop.
Bash CLI skeleton + debug reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
#/ Sample command to perform update and query it's status | |
#/ | |
#/ Usage: <SELF_NAME> [-h|--help] <command> | |
#/ | |
#/ Available commands: | |
#/ one - perform some update, idempotent | |
#/ usage: <SELF_NAME> one <arg1> [arg2] | |
#/ two - query status of update | |
#/ usage: <SELF_NAME> two <arg1> | |
#/ | |
#/ Environment variables: | |
#/ DEBUG=1 - troubleshoot logic using config.debug file | |
#/ FORCE=1 - enforce action, disables idempotence | |
set -eu -o pipefail -o errtrace -o functrace | |
test "${BASH_VERSINFO[0]}" -lt 4 || shopt -s inherit_errexit nullglob compat"${BASH_COMPAT=42}" | |
# === prereq === # | |
: "${DEBUG:=}" | |
: "${FORCE:=}" | |
readonly DEBUG FORCE | |
IS_SOURCED=$(test "${BASH_SOURCE[0]}" == "${0}" || echo 1) | |
SELF_FILE=$(\grep -E '^(\.|\/)' <<< "${BASH_SOURCE[0]}" || echo "./${BASH_SOURCE[0]}") | |
WORK_DIR=$(\pwd -P) | |
DEBUG_FILE="${WORK_DIR}/${SELF_FILE##*/}.dbg" | |
readonly IS_SOURCED SELF_FILE WORK_DIR DEBUG_FILE | |
# === func === # | |
main() { | |
test -z "${DEBUG}" || { | |
enable_debug "${DEBUG_FILE}" | |
: "Sourced=${IS_SOURCED:-0}" | |
: "WorkDir=${WORK_DIR}" | |
stderr "# sending debug stream into ${DEBUG_FILE##*/} file in current directory ..." | |
} | |
! \grep -Eq "(^|\s)--help|-h(\s|$)" <<< "$*" || usage | |
check_requirements | |
declare cmd="${1:-}" | |
shift || : | |
case "${cmd,,}" in | |
one) cmd_one "$@" ;; | |
two) cmd_two "$@" ;; | |
*) usage "invalid command specified" ;; | |
esac | |
} | |
cmd_one() { | |
declare arg1="${1:-}" | |
declare arg2="${2:-default2}" | |
test -n "${arg1}" || fatal "arg1 is empty" | |
echo "running sub command: one(${arg1}, ${arg2})" | |
} | |
cmd_two() { | |
declare arg1="${1:-}" | |
test -n "${arg1}" || fatal "arg1 is empty" | |
echo "running sub command: two(${arg1})" | |
} | |
enable_debug() { | |
declare file="$1" | |
exec 19> "${file}" | |
export BASH_XTRACEFD=19 | |
shopt -s extdebug | |
declare -g DEBUG_START_MS | |
DEBUG_START_MS=$(unix_milliseconds) | |
readonly DEBUG_START_MS | |
export PS4='+ [$(( $(unix_milliseconds) - $DEBUG_START_MS ))ms] at ${BASH_SOURCE[0]}:${LINENO} in ${FUNCNAME[0]:-main}${FUNCNAME[0]:+()} [pid:${BASHPID},sub:${BASH_SUBSHELL},uid:${EUID}] ' | |
set -x | |
: "OS=${OSTYPE}" | |
: "Bash=${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]}" | |
: "BashOpts=${BASHOPTS}" | |
} | |
check_requirements() { | |
printf '4.1\n%s\n' "${BASH_VERSION}" | \sort -CV || fatal "bash 4.1+ is required, got ${BASH_VERSION} ..." | |
for cmd in jq perl sed; do | |
command -v "${cmd}" &>/dev/null || fatal "command '${cmd}' is missing" | |
done | |
declare version | |
version=$(\jq --version 2>&1 | \awk -F'[ -]' 'OFS="-" {$1="";gsub("^-+","",$0)}1') | |
printf '1.6\n%s' "${version}" | \sort -CV || fatal "\jq 1.6+ is required, got ${version} ..." | |
} | |
fatal() { | |
printf -- "Error: %s\n" "${@}" >&2 | |
exit 1 | |
} | |
stderr() { | |
printf -- "%s\n" "${@}" >&2 | |
} | |
unix_milliseconds() { | |
test "${BASH_VERSINFO[0]}" -lt 5 || { | |
date +%s%3N | |
return | |
} | |
echo $(( "${EPOCHREALTIME/./}" / 1000 )) | |
} | |
usage() { | |
declare err_msg="${1:-}" | |
\grep '^#/' "${SELF_FILE}" | \cut -c4- | \sed -e "s/<SELF_NAME>/${SELF_FILE##*/}/" | |
test -n "${err_msg}" || exit 0 | |
echo | |
fatal "${err_msg}" | |
} | |
readlinkf() { | |
\perl -MCwd -l -e 'print Cwd::abs_path shift' "$1" | |
} | |
indent() { | |
\sed -e 's/^/ /' | |
} | |
# === main === # | |
test -n "${IS_SOURCED}" || { | |
main "$@" | |
exit 0 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -e | |
fatal() { | |
printf -- "Error: %s\n" "${@}" >&2 | |
exit 1 | |
} | |
declare file="${1:-}" | |
declare line prev | |
test -n "${file}" || fatal 'provide filename' | |
test -f "${file}" || fatal 'file is missing or not readable' | |
while IFS= read -r line; do | |
if test "${line:0:1}" != "+"; then | |
# 2nd+ multiline | |
echo "${line}" | |
continue | |
fi | |
declare -i t1=0 | |
declare -i t2=0 | |
if test "${prev}" == ""; then | |
prev="${line}" | |
continue | |
fi | |
t1=$(echo "${prev}" | sed -r -e 's,.*^\++\s+\[([0-9]+)ms\].*,\1,') | |
t2=$(echo "${line}" | sed -r -e 's,.*^\++\s+\[([0-9]+)ms\].*,\1,') | |
elapsed=$((t2-t1)) | |
echo "${prev}" | sed -r -e "s/\[([0-9]+ms)\]/[\1+${elapsed}ms]/" | |
prev="${line}" | |
done < "$file" | |
if test "${prev}" != ""; then | |
echo "${prev}" | sed -r -e "s/\[([0-9]+ms)\]/[\1+0ms]/" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment