Làm cách nào để tìm số dòng trong Bash khi xảy ra lỗi?


21

Làm thế nào để bạn tìm thấy số dòng trong Bash nơi xảy ra lỗi?

Thí dụ

Tôi tạo tập lệnh đơn giản sau với số dòng để giải thích những gì chúng ta cần. Kịch bản sẽ sao chép các tập tin từ

cp $file1 $file2
cp $file3 $file4

Khi một trong những cp lệnh thất bại thì chức năng sẽ thoát với thoát 1 . Chúng tôi muốn thêm khả năng cho chức năng để in lỗi với số dòng (ví dụ: 8 hoặc 12).

Điều này có thể không?

Kịch bản mẫu

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


Bạn có thể sử dụng set -xvà / hoặc set -vđể theo dõi những gì đã được thực hiện. Không chính xác những gì bạn yêu cầu nhưng nó cũng có thể sẽ hữu ích.
Rolf

Câu trả lời:


29

Thay vì sử dụng chức năng của bạn, tôi sẽ sử dụng phương pháp này thay thế:

$ 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"

Điều này hoạt động bằng cách bẫy trên ERR và sau đó gọi failure()hàm bằng số dòng + lệnh bash hiện tại đã được thực thi.

Thí dụ

Ở đây tôi đã không thực hiện bất kỳ chăm sóc để tạo ra các tập tin, f1, f2, f3, hoặc f4. Khi tôi chạy đoạn script trên:

$ ./yael.bash
cp: cannot stat f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"

Nó không thành công, báo cáo số dòng cộng với lệnh đã được thực thi.


14

Ngoài việc LINENOchứa số dòng hiện tại, còn có các mảng BASH_LINENOFUNCNAME(và BASH_SOURCE) có chứa tên hàm và số dòng chúng được gọi từ đó.

Vì vậy, bạn có thể làm một cái gì đó như thế này:

#!/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

Chạy mà sẽ in

'that thing' failed with exit code 123 in function 'foo' at line 9.

Nếu bạn dùng set -e hoặc trap ... ERRđể tự động phát hiện lỗi, lưu ý rằng chúng có một số cảnh báo. Cũng khó bao gồm một mô tả về những gì tập lệnh đang làm vào thời điểm đó (như bạn đã làm trong ví dụ của mình), mặc dù điều đó có thể hữu ích hơn cho người dùng thông thường hơn là chỉ số dòng.

Xem ví dụ này cho các vấn đề với set -e và những người khác:


13

Bash có một biến tích $LINENOhợp được thay thế bằng số dòng hiện tại khi trong một câu lệnh, vì vậy bạn có thể làm

in_case_fail $? "at $LINENO: cp $file1 $file2"

Bạn cũng có thể thử sử dụng trap ... ERRchạy khi lệnh thất bại (nếu kết quả không được kiểm tra). Ví dụ:

trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR

Sau đó, nếu một lệnh như cp $file1 $file2thất bại, bạn sẽ nhận được thông báo lỗi với số dòng và thoát. Bạn cũng sẽ tìm thấy lệnh bị lỗi trong biến $BASH_COMMAND(mặc dù không có bất kỳ chuyển hướng nào, v.v.).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.