Bash 스크립트에서 오류 발생
Bash 스크립트에서 "Test cases Failed !!!"메시지와 함께 오류를 발생시키고 싶습니다. Bash에서 어떻게할까요?
예를 들면 :
if [ condition ]; then
raise error "Test cases failed !!!"
fi
이는 오류 메시지를 저장할 위치에 따라 다릅니다.
다음을 수행 할 수 있습니다.
echo "Error!" > logfile.log
exit 125
또는 다음 :
echo "Error!" 1>&2
exit 64
예외가 발생하면 프로그램 실행이 중지됩니다.
당신은 또한 같은 수 있습니다 exit xxx
어디에 xxx
당신이 (0 ~ 255) 운영 체제로 복귀 할 수있는 오류 코드입니다. 이곳까지 125
와 64
당신이 종료 할 수 있습니다 무작위 코드입니다. 프로그램이 비정상적으로 중지되었음을 OS에 표시해야하는 경우 (예 : 오류 발생) 0이 아닌 종료 코드 를 에 전달해야 합니다 exit
.
@chepner가 지적했듯이 할 수 있습니다 . 이는 지정되지 않은 오류를exit 1
의미 합니다 .
기본 오류 처리
테스트 케이스 실행기가 실패한 테스트에 대해 0이 아닌 코드 를 반환하는 경우 다음 과 같이 간단히 작성할 수 있습니다.
test_handler test_case_x; test_result=$?
if ((test_result != 0)); then
printf '%s\n' "Test case x failed" >&2 # write error message to stderr
exit 1 # or exit $test_result
fi
또는 더 짧게 :
if ! test_handler test_case_x; then
printf '%s\n' "Test case x failed" >&2
exit 1
fi
또는 가장 짧은 :
test_handler test_case_x || { printf '%s\n' "Test case x failed" >&2; exit 1; }
test_handler의 종료 코드로 종료하려면 :
test_handler test_case_x || { ec=$?; printf '%s\n' "Test case x failed" >&2; exit $ec; }
고급 오류 처리
보다 포괄적 인 접근 방식을 원할 경우 오류 처리기를 사용할 수 있습니다.
exit_if_error() {
local exit_code=$1
shift
[[ $exit_code ]] && # do nothing if no error code passed
((exit_code != 0)) && { # do nothing if error code is 0
printf 'ERROR: %s\n' "$@" >&2 # we can use better logging here
exit "$exit_code" # we could also check to make sure
# error code is numeric when passed
}
}
그런 다음 테스트 케이스를 실행 한 후 호출하십시오.
run_test_case test_case_x
exit_if_error $? "Test case x failed"
또는
run_test_case test_case_x || exit_if_error $? "Test case x failed"
다음과 같은 오류 처리기의 장점 exit_if_error
은 다음 과 같습니다.
- 로깅 , 스택 추적 인쇄 , 알림, 정리 수행 등과 같은 모든 오류 처리 논리 를 한 곳에서 표준화 할 수 있습니다 .
- 에러 핸들러가 에러 코드를 인자로 받도록함으로써, 우리는
if
에러에 대한 종료 코드를 테스트 하는 복잡한 블록 으로부터 호출자를 보호 할 수 있습니다. - 시그널 핸들러 ( trap 사용 )가 있으면 거기에서 오류 핸들러를 호출 할 수 있습니다.
오류 처리 및 로깅 라이브러리
다음은 오류 처리 및 로깅의 완전한 구현입니다.
https://github.com/codeforester/base/blob/master/lib/stdlib.sh
관련 게시물
- Bash에서 오류 처리
- Bash Hackers Wiki 의 'caller'내장 명령
- Linux에 표준 종료 상태 코드가 있습니까?
- BashFAQ / 105--e (또는 set -o errexit 또는 trap ERR)가 예상 한대로 작동하지 않는 이유는 무엇입니까?
- 당량
__FILE__
,__LINE__
배시에 - Bash에 TRY CATCH 명령이 있습니까?
- 오류 처리기에 스택 추적을 추가하려면 다음 게시물을 참조하십시오. Bash 스크립트에 의해 호출 된 실행 된 프로그램 추적
- 쉘 스크립트의 특정 오류 무시
- 쉘 파이프에서 오류 코드 포착
- 쉘 스크립트 내에서 로그 상세도를 어떻게 관리합니까?
- Bash에서 함수 이름과 줄 번호를 기록하는 방법은 무엇입니까?
- Bash에서 이중 대괄호 [[]]가 단일 대괄호 []보다 선호됩니까?
이 문제에 접근 할 수있는 몇 가지 방법이 더 있습니다. 요구 사항 중 하나가 몇 가지 셸 명령이 포함 된 셸 스크립트 / 함수를 실행하고 스크립트가 성공적으로 실행되었는지 확인하고 실패시 오류를 발생시키는 것이라고 가정합니다.
의 셸 명령은 일반적으로 반환 된 종료 코드에 의존하여 예상치 못한 이벤트로 인해 성공했는지 실패했는지 셸에 알립니다.
그래서 당신이 원하는 것은이 두 가지 범주에 속합니다.
- 오류시 종료
- 오류시 종료 및 정리
수행하려는 작업에 따라 사용할 수있는 셸 옵션이 있습니다. 첫 번째 경우 쉘은 옵션을 제공 set -e
하고 두 번째 경우에는 다음을 수행 할 수 있습니다 trap
.EXIT
exit
내 스크립트 / 함수에서 사용해야합니까 ?
exit
일반적으로 사용 하면 가독성이 향상됩니다. 특정 루틴에서 답을 알고 나면 즉시 호출 루틴을 종료하려고합니다. 루틴이 오류를 감지 한 후 더 이상 정리할 필요가없는 방식으로 정의 된 경우 즉시 종료하지 않으면 더 많은 코드를 작성해야합니다.
따라서 스크립트를 정리하기 위해 스크립트에서 정리 작업을 수행해야하는 경우에는를 사용 하지 않는 것이 좋습니다 exit
.
종료시 set -e
오류에 사용해야 합니까?
아니!
set -e
쉘에 "자동 오류 감지"를 추가하려는 시도였습니다. 그 목표는 오류가 발생할 때마다 쉘이 중단되도록하는 것이었지만 예를 들어 많은 잠재적 인 함정이 있습니다.
if 테스트의 일부인 명령은 면역입니다. 이 예에서
test
존재하지 않는 디렉토리 에 대한 검사에서 중단 될 것으로 예상하면 그렇지 않으며 else 조건으로 이동합니다.set -e f() { test -d nosuchdir && echo no dir; } f echo survived
마지막 명령이 아닌 파이프 라인의 명령은 면역입니다. 아래 예에서는 가장 최근에 실행 된 (가장 오른쪽) 명령의 종료 코드가 (
cat
) 로 간주 되고 성공했기 때문입니다. 이것은set -o pipefail
옵션 으로 설정함으로써 피할 수 있지만 여전히 경고입니다.set -e somecommand that fails | cat - echo survived
사용 권장- trap
종료시
평결은을 사용하는 대신 맹목적으로 종료하는 대신 오류를 처리 할 수 있도록 의사 신호 에 set -e
a trap
를 사용하는 것 입니다 ERR
.
ERR
트랩은 쉘 자체가 아닌 에러 코드와 함께 종료 할 때 코드를 실행하지만,하지 때 조건의 일부 (경우처럼 아니라고 쉘에 의한 명령의 실행 cmd
, 또는 cmd ||
0이 아닌 종료 상태) 종료 .
일반적인 관행은 어떤 라인과 종료 원인에 대한 추가 디버그 정보를 제공하기 위해 트랩 핸들러를 정의하는 것입니다. ERR
신호 를 유발 한 마지막 명령의 종료 코드는 이 시점에서 계속 사용할 수 있습니다.
cleanup() {
exitcode=$?
printf 'error condition hit\n' 1>&2
printf 'exit code returned: %s\n' "$exitcode"
printf 'the command executing at the time of the error was: %s\n' "$BASH_COMMAND"
printf 'command present on line: %d' "${BASH_LINENO[0]}"
# Some more clean up code can be added here before exiting
exit $exitcode
}
실패한 스크립트 위에 다음과 같이이 핸들러를 사용합니다.
trap cleanup ERR
이것을 false
15 행에 포함 된 간단한 스크립트에 합치면 다음과 같은 정보를 얻을 수 있습니다.
error condition hit
exit code returned: 1
the command executing at the time of the error was: false
command present on line: 15
는 trap
또한 오류에 관계없이 신호에서 쉘 완료 (예 : 쉘 스크립트 종료)시 정리를 실행하는 옵션을 제공합니다 EXIT
. 동시에 여러 신호를 트랩 할 수도 있습니다. 트랩에 지원되는 신호 목록은 trap.1p-Linux 매뉴얼 페이지 에서 찾을 수 있습니다 .
주의해야 할 또 다른 사항은 하위 셸을 다루는 경우 제공된 메서드가 작동하지 않는다는 점을 이해하는 것입니다.이 경우 자체 오류 처리를 추가해야 할 수도 있습니다.
하위 셸에서
set -e
작동하지 않습니다. 는false
서브 쉘로 제한되고 부모 쉘에 전달되지 없구요. 여기에서 오류 처리를 수행하려면 수행 할 고유 한 논리를 추가하십시오.(false) || false
set -e (false) echo survived
또한 마찬가지
trap
입니다. 아래 논리는 위에서 언급 한 이유로 작동하지 않습니다.trap 'echo error' ERR (false)
다음은 STDERR에 실패한 모든 항목의 마지막 인수를 인쇄하고 실패한 행을보고하며 종료 코드로 행 번호를 사용하여 스크립트를 종료하는 간단한 트랩입니다. 이것들이 항상 훌륭한 아이디어는 아니지만 이것은 당신이 만들 수있는 몇 가지 창의적인 응용 프로그램을 보여줍니다.
trap 'echo >&2 "$_ at $LINENO"; exit $LINENO;' ERR
나는 그것을 테스트하기 위해 루프가있는 스크립트에 넣었습니다. 난 그냥 임의의 숫자에 대한 히트를 확인합니다. 실제 테스트를 사용할 수 있습니다. 보석금이 필요한 경우 던지고 싶은 메시지와 함께 false (트랩을 트리거 함)를 호출합니다.
For elaborated functionality, have the trap call a processing function. You can always use a case statement on your arg ($_) if you need to do more cleanup, etc. Assign to a var for a little syntactic sugar -
trap 'echo >&2 "$_ at $LINENO"; exit $LINENO;' ERR
throw=false
raise=false
while :
do x=$(( $RANDOM % 10 ))
case $x in
0) $throw "DIVISION BY ZERO" ;;
3) $raise "MAGIC NUMBER" ;;
*) echo got $x ;;
esac
done
Sample output:
# bash tst
got 2
got 8
DIVISION BY ZERO at 6
# echo $?
6
Obviously, you could
runTest1 "Test1 fails" # message not used if it succeeds
Lots of room for design improvement.
The draw backs include the fact that false
isn't pretty (thus the sugar), and other things tripping the trap might look a little stupid. Still, I like this method.
You have 2 options: Redirect the output of the script to a file, Introduce a log file in the script and
- Redirecting output to a file:
Here you assume that the script outputs all necessary info, including warning and error messages. You can then redirect the output to a file of your choice.
./runTests &> output.log
The above command redirects both the standard output and the error output to your log file.
Using this approach you don't have to introduce a log file in the script, and so the logic is a tiny bit easier.
- Introduce a log file to the script:
In your script add a log file either by hard coding it:
logFile='./path/to/log/file.log'
or passing it by a parameter:
logFile="${1}" # This assumes the first parameter to the script is the log file
It's a good idea to add the timestamp at the time of execution to the log file at the top of the script:
date '+%Y%-m%d-%H%M%S' >> "${logFile}"
You can then redirect your error messages to the log file
if [ condition ]; then
echo "Test cases failed!!" >> "${logFile}";
fi
This will append the error to the log file and continue execution. If you want to stop execution when critical errors occur, you can exit
the script:
if [ condition ]; then
echo "Test cases failed!!" >> "${logFile}";
# Clean up if needed
exit 1;
fi
Note that exit 1
indicates that the program stop execution due to an unspecified error. You can customize this if you like.
Using this approach you can customize your logs and have a different log file for each component of your script.
If you have a relatively small script or want to execute somebody else's script without modifying it the the first approach is more suitable.
If you always want the log file to be at the same location, this is the better option of the 2. Also if you have created a big script with multiple components then you may want to log each part differently and the second approach is your only option.
I often find it useful to write a function to handle error messages so the code is cleaner overall.
# Usage: die [exit_code] [error message]
die() {
local code=$? now=$(date +%T.%N)
if [ "$1" -ge 0 ] 2>/dev/null; then # assume $1 is an error code if numeric
code="$1"
shift
fi
echo "$0: ERROR at ${now%???}${1:+: $*}" >&2
exit $code
}
This takes the error code from the previous command and uses it as the default error code when exiting the whole script. It also notes the time, with microseconds where supported (GNU date's %N
is nanoseconds, which we truncate to microseconds later).
If the first option is zero or a positive integer, it becomes the exit code and we remove it from the list of options. We then report the message to standard error, with the name of the script, the word "ERROR", and the time (we use parameter expansion to truncate nanoseconds to microseconds, or for non-GNU times, to truncate e.g. 12:34:56.%N
to 12:34:56
). A colon and space are added after the word ERROR, but only when there is a provided error message. Finally, we exit the script using the previously determined exit code, triggering any traps as normal.
Some examples (assume the code lives in script.sh
):
if [ condition ]; then die 123 "condition not met"; fi
# exit code 123, message "script.sh: ERROR at 14:58:01.234564: condition not met"
$command |grep -q condition || die 1 "'$command' lacked 'condition'"
# exit code 1, "script.sh: ERROR at 14:58:55.825626: 'foo' lacked 'condition'"
$command || die
# exit code comes from command's, message "script.sh: ERROR at 14:59:15.575089"
참고URL : https://stackoverflow.com/questions/30078281/raise-error-in-a-bash-script
'development' 카테고리의 다른 글
그렇다면 사용자 정의 HTML 속성이 유효한 XHTML이 아니라면 어떻게 될까요? (0) | 2020.10.12 |
---|---|
JSON.stringify ()의 출력에서 특정 값 숨기기 (0) | 2020.10.12 |
명령 줄 도구 bash (git)가 작동하지 않음-macOS Sierra 최종 릴리스 후보 (0) | 2020.10.12 |
.NET에 직렬화 가능한 일반 키 / 값 쌍 클래스가 있습니까? (0) | 2020.10.12 |
emacs에서 줄 / 영역을 위아래로 이동 (0) | 2020.10.12 |