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:
Izaak Beekman 2017-02-10 09:03:07 -05:00 committed by Kevin van Zonneveld
parent 7f9419cda0
commit 7cf9ea708d
7 changed files with 85 additions and 29 deletions

View File

@ -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
View File

@ -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

View File

@ -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
View File

@ -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}"

View File

@ -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 "✓"

View File

@ -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 [ info] Cleaning up. Done

View File

@ -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;