È possibile ottenere da quale linea è stato inviato il segnale ERR?
Sì, LINENO
e le BASH_LINENO
variabili sono utili per ottenere la linea di errore e le linee che la portano.
O forse sto sbagliando tutto?
No, manca solo l' -q
opzione con grep ...
echo hello | grep -q "asdf"
... Con l' -q
opzione grep
tornerà 0
per true
e 1
per false
. E in Bash trap
non è Trap
...
trap "_func" ERR
... ho bisogno di una soluzione nativa ...
Ecco un trapper che potresti trovare utile per il debug di cose che hanno una complessità ciclomatica un po 'più ...
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}
}
... e uno script di utilizzo di esempio per esporre le sottili differenze su come impostare la trappola sopra per la traccia delle funzioni ...
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'
Quanto sopra è stato testato su Bash versione 4+, quindi lascia un commento se è necessario qualcosa per le versioni precedenti alla quattro o Apri un problema se non riesce a intercettare gli errori sui sistemi con una versione minima di quattro.
I principali takeaway sono ...
set -E -o functrace
trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
Le virgolette singole vengono utilizzate intorno alla chiamata della funzione e le virgolette doppie sono intorno ai singoli argomenti
I riferimenti a LINENO
e BASH_LINENO
vengono passati invece dei valori correnti, sebbene ciò possa essere abbreviato nelle versioni successive di linked to trap, in modo tale che la riga di errore finale lo trasformi in output
I valori di BASH_COMMAND
e exit status ( $?
) vengono passati, in primo luogo per ottenere il comando che ha restituito un errore, e in secondo luogo per garantire che il trap non si attivi su stati non di errore
E mentre altri potrebbero non essere d'accordo, trovo che sia più semplice creare un array di output e usare printf per stampare ogni elemento dell'array sulla propria riga ...
printf '%s\n' "${_output_array[@]}" >&2
... anche il >&2
bit alla fine fa sì che gli errori vadano dove dovrebbero (errore standard) e consente di catturare solo errori ...
## ... to a file...
some_trapped_script.sh 2>some_trapped_errros.log
## ... or by ignoring standard out...
some_trapped_script.sh 1>/dev/null
Come mostrato da questi e altri esempi su StackTranslate.it, ci sono molti modi per creare un aiuto per il debug usando le utility integrate.
bashdb
. Sembra che il primo argomentotrap
possa contenere variabili che vengono valutate nel contesto desiderato. Quinditrap 'echo $LINENO' ERR'
dovrebbe funzionare.