Bash에서 오류가 발생한 줄 번호를 찾는 방법은 무엇입니까?
예
우리에게 필요한 것을 설명하기 위해 줄 번호가 포함된 다음과 같은 간단한 스크립트를 만들었습니다. 스크립트는 다음에서 파일을 복사합니다.
cp $file1 $file2
cp $file3 $file4
cp
명령 중 하나가 실패하면 함수가 종료됩니다.1번출구. 우리는 이 함수에 오류와 줄 번호(예: 8 또는 12)를 인쇄하는 기능을 추가하고 싶습니다.
가능합니까?
샘플 스크립트
1 #!/bin/bash
2
3
4 function in_case_fail {
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6 }
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14
답변1
귀하의 기능을 사용하는 대신 다음 방법을 사용하겠습니다.
$ cat yael.bash
#!/bin/bash
set -eE -o functrace
file1=f1
file2=f2
file3=f3
file4=f4
failure() {
local lineno=$1
local msg=$2
echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR
cp -- "$file1" "$file2"
cp -- "$file3" "$file4"
이는 failure()
ERR을 포착한 다음 현재 줄 번호 + 실행된 bash 명령을 사용하여 함수를 호출함으로써 수행됩니다.
예
f1
여기서는 , f2
, 파일 생성에 신경을 쓰지 f3
않았습니다 f4
. 위 스크립트를 실행하면:
$ ./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"
실패하고 행 번호와 실행된 명령이 보고됩니다.
답변2
현재 줄 번호를 포함하는 것 외에도 함수 이름과 함수가 호출된 줄 번호를 포함하는 및 (및 ) 배열 LINENO
도 있습니다 .BASH_LINENO
FUNCNAME
BASH_SOURCE
그래서 당신은 이것을 할 수 있습니다 :
#!/bin/bash
error() {
printf "'%s' failed with exit code %d in function '%s' at line %d.\n" "${1-something}" "$?" "${FUNCNAME[1]}" "${BASH_LINENO[0]}"
}
foo() {
( exit 0 ) || error "this thing"
( exit 123 ) || error "that thing"
}
foo
실행하면 인쇄됩니다.
'that thing' failed with exit code 123 in function 'foo' at line 9.
set -e
, 또는 을 사용하여 trap ... ERR
오류를 자동으로 감지하는 경우 몇 가지 주의 사항이 있다는 점에 유의하세요. 또한 해당 순간에 스크립트가 수행하는 작업에 대한 설명을 포함하는 것이 더 어렵습니다(예에서와 같이). 이는 줄 번호보다 일반 사용자에게 더 유용할 수 있습니다.
예를 들어 다음 질문 set -e
과 기타 사항을 참조하세요.
답변3
$LINENO
Bash에는 명령문 내부에서 현재 줄 번호로 대체되는 내장 변수가 있으므로 다음을 수행할 수 있습니다.
in_case_fail $? "at $LINENO: cp $file1 $file2"
trap ... ERR
명령이 실패할 경우(결과가 테스트되지 않은 경우) 실행되는 명령을 사용해 볼 수도 있습니다 . 예를 들어:
trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR
그런 다음 유사한 명령이 cp $file1 $file2
실패하면 줄 번호가 포함된 오류 메시지를 받고 종료됩니다. 또한 변수의 명령에 오류가 있음을 알 수 있습니다 $BASH_COMMAND
(리디렉션 등은 없지만).
답변4
list of fns [list of line numbers]
나는 스크립트가 함수 안에 있는 것처럼 스택 추적을 포함하고 그렇지 않으면 스크립트 줄 번호를 포함하는 다음을 사용하기로 결정했습니다 . 또한 fn 및 비 fn 기반 스크립트를 사용한 실험 후에 확장된 이전 답변에도 감사드립니다.
set -eE -o functrace
failure() {
local lineno=$2
local fn=$3
local exitstatus=$4
local msg=$5
local lineno_fns=${1% 0}
if [[ "$lineno_fns" != "0" ]] ; then
lineno="${lineno} ${lineno_fns}"
fi
echo "${BASH_SOURCE[1]}:${fn}[${lineno}] Failed with status ${exitstatus}: $msg"
}
trap 'failure "${BASH_LINENO[*]}" "$LINENO" "${FUNCNAME[*]:-script}" "$?" "$BASH_COMMAND"' ERR
따라서 간단한 명령 실패는 다음과 같습니다.
/tmp/b:script[32] Failed with status 1: cp fred john
및 중첩된 함수(hello1이 hello2를 호출함):
/tmp/b:hello2 hello1 main[24 19 29] Failed with status 1: cp john 22
나는 가끔 추가 정보를 제공하는 종료 상태를 보고하는데, 다른 사람들과 달리 스크립트의 전체 경로 이름을 원합니다.
신호로 인한 이탈을 보고하려면 추가 작업이 필요합니다.