print out variables in the failed command
authorIan Kelling <iank@fsf.org>
Thu, 15 Jul 2021 19:37:15 +0000 (15:37 -0400)
committerIan Kelling <iank@fsf.org>
Thu, 15 Jul 2021 19:37:15 +0000 (15:37 -0400)
err

diff --git a/err b/err
index a5d37524b58204af2203b735c18ca2678e327f66..ff4c498b440d064bcf04cfabe4a23c1c1e2cba7d 100644 (file)
--- a/err
+++ b/err
@@ -49,6 +49,10 @@ if ! test "$BASH_VERSION"; then echo "error: shell is not bash" >&2; exit 1; fi
 # Note: In interactive shell, stack calling line number is not
 # available, so we print function definition lines.
 #
+# Note: This works like set -e, which has one unintuitive feature: If
+# you use a function as part of a conditional, eg: func && come_cmd, a
+# failed command within func won't trigger an error.
+#
 # Globals
 #
 #  err_catch_ignore  Array containing glob patterns to test against
@@ -120,31 +124,67 @@ err-allow() {
 #
 #######################################
 err-exit() {
-  local err=$? pipestatus="${PIPESTATUS[*]}"
+  # vars have _ prefix so that we can inspect existing set vars without
+  # too much overwriting of them.
+  local _err=$? _pipestatus="${_pipestatus[*]}"
 
   # This has to come before most things or vars get changed
-  local msg="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err"
-  if [[ $pipestatus != "$err" ]]; then
-    msg+=", PIPESTATUS: $pipestatus"
+  local _msg="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $_err"
+  local _cmdr="$BASH_COMMAND" # command right. we chop of the left, keep the right.
+
+  if [[ $_pipestatus != "$_err" ]]; then
+    _msg+=", PIPESTATUS: $_pipestatus"
   fi
   set +x
   if [[ $1 == -* ]]; then
-    err=${1#-}
+    _err=${1#-}
     shift
-  elif (( ! err )); then
-    err=1
+  elif (( ! _err )); then
+    _err=1
   fi
   if [[ $1 ]]; then
-    msg="$1"
+    _msg="$1"
   fi
-  printf "%s\n" "$msg" >&2
+
+  ## Begin printing vars from within BASH_COMMAND ##
+  local _var _chars _l
+  local -a _vars
+  while [[ $_cmdr ]]; do
+    _chars="${#_cmdr}"
+    _cmdr="${_cmdr#*$}"
+    _cmdr="${_cmdr#{}"
+    if [[ $_chars == ${#_cmdr} ]]; then
+      break
+    fi
+    _var="${_cmdr%%[^a-zA-Z0-9_]*}"
+    # debug:
+    #echo var = $_var _cmdr = $_cmdr
+    if [[ ! $_var || $_var == [0-9]* ]]; then
+      continue
+    fi
+    _vars+=("${_var}=*")
+  done
+  # in my small test, this took 50% longer than piping to grep.
+  # That seems a small enough penalty to stay in bash here.
+  if (( ${#_vars[@]} )); then
+    set |& while read -r _l; do
+             for _var in "${_vars[@]}"; do
+               if [[ $_l == $_var ]]; then
+                 printf "%s\n" "$_l" >&2
+               fi
+             done
+           done
+  fi
+  ## End printing vars from within BASH_COMMAND ##
+
+  printf "%s\n" "$_msg" >&2
   err-bash-trace 2
   set -e # err trap does not work within an error trap
   if type -t err-cleanup >/dev/null; then
     err-cleanup
   fi
-  printf "%s: exiting with status %s\n" "$0" "$err" >&2
-  exit $err
+  printf "%s: exiting with status %s\n" "$0" "$_err" >&2
+  exit $_err
 }
 
 #######################################
@@ -251,4 +291,3 @@ _err-bash-trace-interactive() {
     return 0
   fi
 }
-