Ist es möglich zu erfahren, von welcher Leitung das ERR-Signal gesendet wurde?
Ja, LINENO
und BASH_LINENO
Variablen sind nützlich, um die Fehlerlinie und die dazu führenden Linien zu ermitteln.
Oder mache ich das vielleicht falsch?
Nein, nur fehlende -q
Option mit grep ...
echo hello | grep -q "asdf"
... Mit der -q
Option grep
wird 0
für true
und 1
für zurückkehren false
. Und in Bash ist es trap
nicht Trap
...
trap "_func" ERR
... ich brauche eine native Lösung ...
Hier ist ein Trapper, der nützlich sein könnte, um Dinge zu debuggen, die eine etwas zyklomatischere Komplexität haben ...
failure.sh
## Outputs Front-Mater formatted failures for functions not returning 0
## Use the following line after sourcing this file to set failure trap
## trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
failure(){
local -n _lineno="${1:-LINENO}"
local -n _bash_lineno="${2:-BASH_LINENO}"
local _last_command="${3:-${BASH_COMMAND}}"
local _code="${4:-0}"
## Workaround for read EOF combo tripping traps
if ! ((_code)); then
return "${_code}"
fi
local _last_command_height="$(wc -l <<<"${_last_command}")"
local -a _output_array=()
_output_array+=(
'---'
"lines_history: [${_lineno} ${_bash_lineno[*]}]"
"function_trace: [${FUNCNAME[*]}]"
"exit_code: ${_code}"
)
if [[ "${#BASH_SOURCE[@]}" -gt '1' ]]; then
_output_array+=('source_trace:')
for _item in "${BASH_SOURCE[@]}"; do
_output_array+=(" - ${_item}")
done
else
_output_array+=("source_trace: [${BASH_SOURCE[*]}]")
fi
if [[ "${_last_command_height}" -gt '1' ]]; then
_output_array+=(
'last_command: ->'
"${_last_command}"
)
else
_output_array+=("last_command: ${_last_command}")
fi
_output_array+=('---')
printf '%s\n' "${_output_array[@]}" >&2
exit ${_code}
}
... und ein Beispiel für ein Verwendungsskript, um die subtilen Unterschiede beim Setzen der obigen Falle für die Funktionsverfolgung aufzudecken ...
example_usage.sh
#!/usr/bin/env bash
set -E -o functrace
## Optional, but recommended to find true directory this script resides in
__SOURCE__="${BASH_SOURCE[0]}"
while [[ -h "${__SOURCE__}" ]]; do
__SOURCE__="$(find "${__SOURCE__}" -type l -ls | sed -n 's@^.* -> \(.*\)@\1@p')"
done
__DIR__="$(cd -P "$(dirname "${__SOURCE__}")" && pwd)"
## Source module code within this script
source "${__DIR__}/modules/trap-failure/failure.sh"
trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
something_functional() {
_req_arg_one="${1:?something_functional needs two arguments, missing the first already}"
_opt_arg_one="${2:-SPAM}"
_opt_arg_two="${3:0}"
printf 'something_functional: %s %s %s' "${_req_arg_one}" "${_opt_arg_one}" "${_opt_arg_two}"
## Generate an error by calling nothing
"${__DIR__}/nothing.sh"
}
## Ignoring errors prevents trap from being triggered
something_functional || echo "Ignored something_functional returning $?"
if [[ "$(something_functional 'Spam!?')" == '0' ]]; then
printf 'Nothing somehow was something?!\n' >&2 && exit 1
fi
## And generating an error state will cause the trap to _trace_ it
something_functional '' 'spam' 'Jam'
Das oben Gesagte wurde mit Bash Version 4+ getestet. Hinterlassen Sie daher einen Kommentar, wenn Versionen vor vier erforderlich sind, oder eröffnen Sie ein Problem, wenn Fehler auf Systemen mit einer Mindestversion von vier nicht abgefangen werden können.
Die wichtigsten Imbissbuden sind ...
set -E -o functrace
-E
bewirkt, dass Fehler innerhalb von Funktionen in die Luft sprudeln
-o functrace
Ursachen ermöglichen mehr Ausführlichkeit, wenn etwas innerhalb einer Funktion fehlschlägt
trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
Um Funktionsaufrufe werden einfache Anführungszeichen und um einzelne Argumente doppelte Anführungszeichen verwendet
Verweise auf LINENO
und BASH_LINENO
werden anstelle der aktuellen Werte übergeben, obwohl dies in späteren Versionen von "Linked to Trap" möglicherweise verkürzt wird, sodass die endgültige Fehlerzeile es zur Ausgabe macht
Die Werte von BASH_COMMAND
und exit status ( $?
) werden übergeben, um erstens den Befehl abzurufen, der einen Fehler zurückgegeben hat, und zweitens, um sicherzustellen, dass der Trap nicht bei fehlerfreien Zuständen ausgelöst wird
Und während andere anderer Meinung sein mögen, finde ich es einfacher, ein Ausgabe-Array zu erstellen und printf zum Drucken jedes Array-Elements in einer eigenen Zeile zu verwenden ...
printf '%s\n' "${_output_array[@]}" >&2
... auch das >&2
Bit am Ende bringt Fehler dahin, wo sie hin sollen (Standardfehler) und ermöglicht das Erfassen nur von Fehlern ...
## ... to a file...
some_trapped_script.sh 2>some_trapped_errros.log
## ... or by ignoring standard out...
some_trapped_script.sh 1>/dev/null
Wie diese und andere Beispiele zu Stack Overflow zeigen, gibt es viele Möglichkeiten, eine Debugging-Hilfe mithilfe integrierter Dienstprogramme zu erstellen.
bashdb
. Es scheint, dass das erste Argumenttrap
Variablen enthalten kann, die im gewünschten Kontext ausgewertet werden. Sollte alsotrap 'echo $LINENO' ERR'
funktionieren.