모든 오류에 대한 함수를 호출하기 위해 트랩을 사용하여 일부 오류 보고서를 작성하려고 합니다.
Trap "_func" ERR
ERR 신호가 전송되는 라인을 얻을 수 있습니까? 쉘은 bash입니다.
이렇게 하면 어떤 명령이 사용되었는지 읽고 보고할 수 있으며 일부 작업을 기록/수행할 수 있습니다.
아니면 내가 다 잘못하고 있는 걸까?
나는 다음을 테스트했습니다.
#!/bin/bash
trap "ECHO $LINENO" ERR
echo hello | grep "asdf"
2를 반환 하고 $LINENO
있습니다. 작동 안함.
답변1
댓글에서 지적했듯이 귀하의 견적이 잘못되었습니다. $LINENO
처음 구문 분석할 때 트랩 줄이 확장되는 것을 방지하려면 작은따옴표가 필요합니다 .
이것은 작동합니다:
#! /bin/bash
err_report() {
echo "Error on line $1"
}
trap 'err_report $LINENO' ERR
echo hello | grep foo # This is line number 9
실행하세요:
$ ./test.sh
Error on line 9
답변2
bash 내장 "발신자"를 사용할 수도 있습니다.
#!/bin/bash
err_report() {
echo "errexit on line $(caller)" >&2
}
trap err_report ERR
echo hello | grep foo
또한 파일 이름도 인쇄합니다.
$ ./test.sh
errexit on line 9 ./test.sh
답변3
ERR 신호가 전송되는 라인을 얻을 수 있습니까?
예, LINENO
변수는 BASH_LINENO
실패한 행과 실패를 일으킨 행을 가져오는 데 유용합니다.
아니면 내가 다 잘못하고 있는 걸까?
아니요, 그냥 빠졌어요-q
그렙 옵션...
echo hello | grep -q "asdf"
... 그리고-q
옵션이 반환 grep
됩니다0
true
그리고1
false
. 배쉬에서는trap
아니요Trap
...
trap "_func" ERR
...기본 솔루션이 필요합니다...
다음은 순환적 복잡성이 더 큰 문제를 디버깅하는 데 유용할 수 있는 트랩퍼입니다.
## 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}
}
...그리고 위의 함수 추적 트랩을 설정하는 방법의 미묘한 차이를 보여주는 샘플 사용 스크립트...
#!/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'
위 테스트는 Bash 버전 4 이상에서 수행되었으므로 4 이전 버전이 필요한 경우 의견을 남겨주세요.이슈를 열다최소 버전이 4인 시스템에서 오류를 포착하지 못하는 경우.
기본테이크아웃예...
set -E -o functrace
-E
함수 내에서 오류가 발생합니다.거품-o functrace
원인을 사용하면 함수 내의 어떤 항목이 실패할 때 더 자세한 정보를 얻을 수 있습니다.
trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
함수 호출에는 작은따옴표가 사용되고 개별 매개변수에는 큰따옴표가 사용됩니다.
참고자료
LINENO
그리고BASH_LINENO
현재 값 대신 전달됩니다. 단, 트랩에 연결된 이후 버전에서는 단축되어 최종 실패 라인이 출력에 포함될 수 있습니다.가치
BASH_COMMAND
및 종료 상태($?
)가 전달되는데, 먼저 오류를 반환하는 명령을 가져오고 두 번째로 오류가 아닌 상태에서 트랩이 트리거되지 않도록 하기 위해 전달됩니다.
다른 사람들은 동의하지 않을 수도 있지만, 출력 배열을 만들고 printf를 사용하여 각 배열 요소를 한 줄에 인쇄하는 것이 더 쉽다는 것을 알았습니다.
printf '%s\n' "${_output_array[@]}" >&2
...게다가>&2
마지막 비트는 오류가 발생해야 하는 위치(표준 오류)에서 오류를 발생시키고 오류만 포착하도록 허용합니다.
## ... to a file...
some_trapped_script.sh 2>some_trapped_errros.log
## ... or by ignoring standard out...
some_trapped_script.sh 1>/dev/null
이것들과다른 예스택 오버플로에는 내장 유틸리티를 사용하여 디버깅 지원을 구축하는 방법이 많이 있습니다.
답변4
@sanmai 및 @unpythonic에서 영감을 받은 또 다른 버전이 있습니다. 오류, 줄 번호 및 종료 상태 주변의 스크립트 줄을 표시합니다. 이는 awk 솔루션보다 간단해 보이기 때문에 tail 및 head를 사용합니다.
가독성을 위해 두 줄로 표시됩니다. 원하는 경우 두 줄을 하나로 병합할 수 있습니다(유지 ;
).
trap 'echo >&2 "Error - exited with status $? at line $LINENO:";
pr -tn $0 | tail -n+$((LINENO - 3)) | head -n7 >&2' ERR
이는 set -eEuo pipefail
(비공식 엄격 모드)
- 정의되지 않은 변수 오류는 가짜 신호를 트리거하지 않고 줄 번호를 제공
ERR
하지만 다른 경우에는 컨텍스트를 표시합니다.
출력 예:
myscript.sh: line 27: blah: command not found
Error - exited with status 127 at line 27:
24 # Do something
25 lines=$(wc -l /etc/passwd)
26 # More stuff
27 blah
28
29 # Check time
30 time=$(date)