Có thể lấy dòng tín hiệu ERR được gửi từ đâu không?
Có, LINENO
và BASH_LINENO
các biến là siêu hữu ích để có được dòng thất bại và các dòng dẫn đến nó.
Hoặc có lẽ tôi đang làm điều này sai?
Không, chỉ thiếu -q
tùy chọn với grep ...
echo hello | grep -q "asdf"
... Với sự -q
lựa chọn grep
sẽ trở lại 0
cho true
và 1
cho false
. Và ở Bash, nó trap
không Trap
...
trap "_func" ERR
... Tôi cần một giải pháp bản địa ...
Đây là một cái bẫy mà bạn có thể thấy hữu ích để gỡ lỗi những thứ có độ phức tạp chu kỳ hơn một chút ...
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}
}
... và một kịch bản sử dụng ví dụ để phơi bày sự khác biệt tinh tế trong cách đặt bẫy ở trên để theo dõi chức năng ...
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'
Ở trên đã thử nghiệm trên Bash phiên bản 4+, vì vậy hãy để lại nhận xét nếu cần một cái gì đó cho các phiên bản trước bốn hoặc Mở một vấn đề nếu nó không bẫy được các lỗi trên các hệ thống có phiên bản tối thiểu là bốn.
Các chính takeaways là ...
set -E -o functrace
trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
Dấu ngoặc đơn được sử dụng xung quanh lệnh gọi hàm và dấu ngoặc kép nằm xung quanh các đối số riêng lẻ
Các tham chiếu đến LINENO
và BASH_LINENO
được truyền thay cho các giá trị hiện tại, mặc dù điều này có thể được rút ngắn trong các phiên bản sau của liên kết với bẫy, do đó, dòng thất bại cuối cùng biến nó thành đầu ra
Các giá trị của BASH_COMMAND
trạng thái thoát và thoát ( $?
) được thông qua, đầu tiên để nhận lệnh trả về lỗi và thứ hai để đảm bảo rằng bẫy không kích hoạt các trạng thái không lỗi
Và trong khi những người khác có thể không đồng ý, tôi thấy việc xây dựng một mảng đầu ra dễ dàng hơn và sử dụng printf để in từng phần tử mảng trên dòng riêng của nó ...
printf '%s\n' "${_output_array[@]}" >&2
... cũng là >&2
bit ở cuối gây ra lỗi ở đâu (lỗi tiêu chuẩn) và cho phép chỉ bắt lỗi ...
## ... to a file...
some_trapped_script.sh 2>some_trapped_errros.log
## ... or by ignoring standard out...
some_trapped_script.sh 1>/dev/null
Như được thể hiện bởi những điều này và các ví dụ khác trên Stack Overflow, có rất nhiều cách để xây dựng một công cụ gỡ lỗi bằng cách sử dụng các tiện ích tích hợp.
bashdb
. Có vẻ như đối số đầu tiêntrap
có thể chứa các biến được đánh giá trong ngữ cảnh mong muốn. Vì vậytrap 'echo $LINENO' ERR'
nên làm việc.