mirror of
https://github.com/kvz/bash3boilerplate.git
synced 2024-12-18 14:26:22 +00:00
Issue 44 issue 21 issue 47 (#85)
* Fix shifting over `--`: don't throw errexit Fixes #21 * Add error trapping (including Ctrl-C) info to FAQ Closes #47 * Add backtracing to help localize errors - Fixes #44 - Backtracing is turned on when the debugging `-d` flag is passed, otherwise backtracing function defined but signal trap not set. - Update main-help fixture due to moving trap * Untabify main.sh Might be a controversial move, but I loath tabs... * Add checks for tab chars and trailing whitespace - Update poor-man's style enforcement script to check for these violations - Better document style guidlines in README with small tweaks * Add a magic variable to indicate if being source if `__i_am_main_script=1 #true` then `main.sh` called directly Fixes #45
This commit is contained in:
parent
7f9419cda0
commit
7cf9ea708d
@ -4,6 +4,11 @@
|
||||
|
||||
Released: Unreleased. [Commit log](https://github.com/kvz/bash3boilerplate/compare/v2.2.0...master)
|
||||
|
||||
- Add magic variable `__i_am_main_script` to distinguish if b3bp is being sourced or called directly (#45, @zbeekman)
|
||||
- Add style checks for tab characters and trailing whitespace (@zbeekman)
|
||||
- Add backtracing to help localize errors (#44, @zbeekman)
|
||||
- Additional FAQ entries (#47, suggested by @gdevenyi, implemented by @zbeekman)
|
||||
- Ensure that shifting over `--` doesn't throw an errexit error (#21, @zbeekman)
|
||||
- Add Pull Request template (#83)
|
||||
|
||||
## v2.2.0
|
||||
|
21
FAQ.md
21
FAQ.md
@ -16,6 +16,8 @@
|
||||
* [You are saying you are portable, but why won't b3bp code run in dash / busybox / posh / ksh / mksh / zsh](#you-are-saying-you-are-portable-but-why-wont-b3bp-code-run-in-dash--busybox--posh--ksh--mksh--zsh)?
|
||||
* [How do I do Operating System detection](#how-do-i-do-operating-system-detection)?
|
||||
* [How do I access a potentially unset (environment) variable](#how-do-i-access-a-potentially-unset-environment-variable)?
|
||||
* [How can I detect or trap CTRL-C and other signals](#how-can-i-detect-or-trap-ctrl-c-and-other-signals)?
|
||||
* [How can I get the PID of my running script](how-can-i-get-the-pid-of-my-running-script)?
|
||||
|
||||
<!--more-->
|
||||
|
||||
@ -172,3 +174,22 @@ NAME3=${NAME3:-Damian}; echo ${NAME3} # echos Damian, $NAME3 is set to Damian
|
||||
```
|
||||
|
||||
This subject is briefly touched on as well in the [Safety and Portability section under point 5](README.md#safety-and-portability). b3bp currently uses [method 1](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L252) when we want to access a variable that could be undeclared, and [method 3](https://github.com/kvz/bash3boilerplate/blob/v2.1.0/main.sh#L31) when we also want to set a default to an undeclared variable, because we feel it is more readable than method 2. We feel `:=` is easily overlooked, and not very beginner friendly. Method 3 seems more explicit in that regard in our humble opinion.
|
||||
|
||||
## How can I detect or trap Ctrl-C and other signals?
|
||||
|
||||
You can trap [Unix signals](https://en.wikipedia.org/wiki/Unix_signal) like [Ctrl-C](https://en.wikipedia.org/wiki/Control-C) with code similar to:
|
||||
|
||||
```bash
|
||||
# trap ctrl-c and call ctrl_c()
|
||||
trap ctrl_c INT
|
||||
|
||||
function ctrl_c() {
|
||||
echo "** Trapped CTRL-C"
|
||||
}
|
||||
```
|
||||
|
||||
See http://mywiki.wooledge.org/SignalTrap for a list of signals, examples, and an in depth discussion.
|
||||
|
||||
## How can I get the PID of my running script?
|
||||
|
||||
The PID of a running script is contained in the `${$}` variable. This is *not* the pid of any subshells. With Bash 4 you can get the PID of your subshell with `${BASHPID}`. For a comprehensive list of Bash built in variables see, e.g., http://www.tldp.org/LDP/abs/html/internalvariables.html
|
||||
|
@ -126,9 +126,11 @@ $ my_script some more args --blah
|
||||
|
||||
### Coding style
|
||||
|
||||
1. Use two spaces for tabs.
|
||||
1. Use two spaces for tabs, do not use tab characters.
|
||||
1. Do not introduce whitespace at the end of lines or on blank lines as they obfuscate version control diffs.
|
||||
1. Use long options (`logger --priority` vs `logger -p`). If you are on the CLI, abbreviations make sense for efficiency. Nevertheless, when you are writing reusable scripts, a few extra keystrokes will pay off in readability and avoid ventures into man pages in the future, either by you or your collaborators. Similarly, we prefer `set -o nounset` over `set -u`.
|
||||
1. Use a single equal sign when checking `if [ "${NAME}" = "Kevin" ]`; double or triple signs are not needed.
|
||||
1. Use a single equal sign when checking `if [[ "${NAME}" = "Kevin" ]]`; double or triple signs are not needed.
|
||||
1. Use the new bash builtin test operator (`[[ ... ]]`) rather than the old single square bracket test operator or explicit call to `test`.
|
||||
|
||||
### Safety and Portability
|
||||
|
||||
|
69
main.sh
69
main.sh
@ -40,6 +40,11 @@ fi
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[${__b3bp_tmp_source_idx:-0}]}")"
|
||||
__base="$(basename "${__file}" .sh)"
|
||||
if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then
|
||||
__i_am_main_script="0" # false
|
||||
else
|
||||
__i_am_main_script="1" # true
|
||||
fi
|
||||
|
||||
# Define the environment variables (and their defaults) that this script depends on
|
||||
LOG_LEVEL="${LOG_LEVEL:-6}" # 7 = debug -> 0 = emergency
|
||||
@ -194,8 +199,8 @@ while read -r __b3bp_tmp_line; do
|
||||
else
|
||||
__b3bp_tmp_re="^'(.*)'$"
|
||||
if [[ "${__b3bp_tmp_init}" =~ ${__b3bp_tmp_re} ]]; then
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
__b3bp_tmp_init="${BASH_REMATCH[1]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@ -218,7 +223,7 @@ if [[ "${__b3bp_tmp_opts:-}" ]]; then
|
||||
|
||||
# start parsing command line
|
||||
set +o nounset # unexpected arguments will cause unbound variables
|
||||
# to be dereferenced
|
||||
# to be dereferenced
|
||||
# Overwrite $arg_<flag> defaults with the actual CLI options
|
||||
while getopts "${__b3bp_tmp_opts}" __b3bp_tmp_opt; do
|
||||
[[ "${__b3bp_tmp_opt}" = "?" ]] && help "Invalid use of script: ${*} "
|
||||
@ -226,22 +231,22 @@ if [[ "${__b3bp_tmp_opts:-}" ]]; then
|
||||
if [[ "${__b3bp_tmp_opt}" = "-" ]]; then
|
||||
# OPTARG is long-option-name or long-option=value
|
||||
if [[ "${OPTARG}" =~ .*=.* ]]; then
|
||||
# --key=value format
|
||||
__b3bp_tmp_long_opt=${OPTARG/=*/}
|
||||
# Set opt to the short option corresponding to the long option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
OPTARG=${OPTARG#*=}
|
||||
# --key=value format
|
||||
__b3bp_tmp_long_opt=${OPTARG/=*/}
|
||||
# Set opt to the short option corresponding to the long option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${__b3bp_tmp_long_opt//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
OPTARG=${OPTARG#*=}
|
||||
else
|
||||
# --key value format
|
||||
# Map long name to short version of option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
# Only assign OPTARG if option takes an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
|
||||
printf -v "OPTARG" '%s' "${@:OPTIND:${!__b3bp_tmp_varname}}"
|
||||
# shift over the argument if argument is expected
|
||||
((OPTIND+=__b3bp_tmp_has_arg_${__b3bp_tmp_opt}))
|
||||
# --key value format
|
||||
# Map long name to short version of option
|
||||
__b3bp_tmp_varname="__b3bp_tmp_opt_long2short_${OPTARG//-/_}"
|
||||
printf -v "__b3bp_tmp_opt" '%s' "${!__b3bp_tmp_varname}"
|
||||
# Only assign OPTARG if option takes an argument
|
||||
__b3bp_tmp_varname="__b3bp_tmp_has_arg_${__b3bp_tmp_opt}"
|
||||
printf -v "OPTARG" '%s' "${@:OPTIND:${!__b3bp_tmp_varname}}"
|
||||
# shift over the argument if argument is expected
|
||||
((OPTIND+=__b3bp_tmp_has_arg_${__b3bp_tmp_opt}))
|
||||
fi
|
||||
# we have set opt/OPTARG to the short value and the argument as OPTARG if it exists
|
||||
fi
|
||||
@ -260,7 +265,9 @@ if [[ "${__b3bp_tmp_opts:-}" ]]; then
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
[[ "${1:-}" = "--" ]] && shift
|
||||
if [[ "${1:-}" = "--" ]] ; then
|
||||
shift
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@ -301,6 +308,23 @@ if [[ "${__b3bp_external_usage:-}" = "true" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
### Signal trapping and backtracing
|
||||
##############################################################################
|
||||
|
||||
function __b3bp_cleanup_before_exit () {
|
||||
info "Cleaning up. Done"
|
||||
}
|
||||
trap __b3bp_cleanup_before_exit EXIT
|
||||
|
||||
# requires `set -o errtrace`
|
||||
__b3bp_err_report() {
|
||||
local error_code
|
||||
error_code=${?}
|
||||
error "Error in ${__file} in function ${1} on line ${2}"
|
||||
exit ${error_code}
|
||||
}
|
||||
# Uncomment the following line for always providing an error backtrace
|
||||
# trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
|
||||
### Command-line argument switches (like -d for debugmode, -h for showing helppage)
|
||||
##############################################################################
|
||||
@ -309,6 +333,8 @@ fi
|
||||
if [[ "${arg_d:?}" = "1" ]]; then
|
||||
set -o xtrace
|
||||
LOG_LEVEL="7"
|
||||
# Enable error backtracing
|
||||
trap '__b3bp_err_report "${FUNCNAME:-.}" ${LINENO}' ERR
|
||||
fi
|
||||
|
||||
# verbose mode
|
||||
@ -338,11 +364,6 @@ fi
|
||||
### Runtime
|
||||
##############################################################################
|
||||
|
||||
function cleanup_before_exit () {
|
||||
info "Cleaning up. Done"
|
||||
}
|
||||
trap cleanup_before_exit EXIT
|
||||
|
||||
info "__file: ${__file}"
|
||||
info "__dir: ${__dir}"
|
||||
info "__base: ${__base}"
|
||||
|
@ -208,9 +208,9 @@ if [[ "$(command -v shellcheck)" ]]; then
|
||||
|
||||
if ! shellcheck --shell=bash --external-sources --color=always \
|
||||
"${file}" >> "${__accptstTmpDir}/shellcheck.err"; then
|
||||
echo "✗"
|
||||
failed="true"
|
||||
continue
|
||||
echo "✗"
|
||||
failed="true"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "✓"
|
||||
|
@ -14,3 +14,4 @@ ACCPTST:STDIO_REPLACE_DATETIMES
|
||||
program or elaborate more on command-line arguments. This section is not
|
||||
parsed and will be added as-is to the help.
|
||||
|
||||
{datetime} UTC [32m[ info][0m Cleaning up. Done
|
||||
|
@ -30,6 +30,12 @@ while (<$fh>) {
|
||||
# highlight double equal sign
|
||||
$errors += s/(\[\[.*)(==)(.*\]\])/$1\033[31m$2\033[0m$3/g;
|
||||
|
||||
# highlight tabs mixed with whitespace at beginning of lines
|
||||
$errors += s/^( *)(\t+ *)/\033[31m\[$2\]\033[0m/;
|
||||
|
||||
# highlight trailing whitespace
|
||||
$errors += s/([ \t]+)$/\033[31m\[$1\]\033[0m/;
|
||||
|
||||
next if (not $errors);
|
||||
print "${file}[$.]: $_";
|
||||
$rc = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user