Có một số cách khác mà bạn có thể tiếp cận vấn đề này. Giả sử một trong những yêu cầu của bạn là chạy một tập lệnh / hàm shell chứa một vài lệnh shell và kiểm tra xem tập lệnh có chạy thành công hay không và ném lỗi trong trường hợp không thành công.
Các lệnh shell thường dựa vào các mã thoát được trả về để cho shell biết nó thành công hay thất bại do một số sự kiện không mong muốn.
Vì vậy, những gì bạn muốn làm thuộc hai loại này
- thoát khỏi lỗi
- thoát và dọn dẹp khi bị lỗi
Tùy thuộc vào cách bạn muốn làm, có các tùy chọn trình bao có sẵn để sử dụng. Đối với trường hợp đầu tiên, vỏ cung cấp một tùy chọn với set -e
và cho phần thứ hai bạn có thể làm một trap
trênEXIT
Tôi có nên sử dụng exit
trong script / function của mình không?
Sử dụng exit
nói chung giúp tăng cường khả năng đọc Trong một số quy trình nhất định, khi bạn biết câu trả lời, bạn muốn thoát khỏi quy trình gọi điện ngay lập tức. Nếu quy trình được định nghĩa theo cách mà nó không yêu cầu phải dọn dẹp thêm khi phát hiện ra lỗi, thì việc không thoát ngay lập tức có nghĩa là bạn phải viết thêm mã.
Vì vậy, trong trường hợp nếu bạn cần thực hiện các hành động dọn dẹp script để làm cho việc chấm dứt script sạch sẽ, thì bạn nên không sử dụng exit
.
Tôi có nên sử dụng set -e
cho lỗi khi thoát không?
Không!
set -e
là một nỗ lực để thêm "phát hiện lỗi tự động" vào trình bao. Mục tiêu của nó là làm cho shell ngừng hoạt động bất kỳ khi nào xảy ra lỗi, nhưng nó đi kèm với rất nhiều cạm bẫy tiềm ẩn, chẳng hạn như
Các lệnh là một phần của kiểm tra if được miễn dịch. Trong ví dụ, nếu bạn mong đợi nó phá vỡ test
kiểm tra trên thư mục không tồn tại, nó sẽ không, nó chuyển sang điều kiện khác
set -e
f() { test -d nosuchdir && echo no dir; }
f
echo survived
Các lệnh trong một đường dẫn không phải là lệnh cuối cùng, được miễn nhiễm. Trong ví dụ dưới đây, vì mã thoát của lệnh được thực thi gần đây nhất (ngoài cùng bên phải) được coi là ( cat
) và nó đã thành công. Điều này có thể tránh được bằng cách cài đặt theo set -o pipefail
tùy chọn nhưng nó vẫn là một cảnh báo.
set -e
somecommand that fails | cat -
echo survived
Được đề xuất để sử dụng - trap
khi thoát
Phán quyết là nếu bạn muốn có thể xử lý một lỗi thay vì thoát ra một cách mù quáng, thay vì sử dụng set -e
, hãy sử dụng một trap
trên ERR
tín hiệu giả.
Cái ERR
bẫy không phải để chạy mã khi trình bao tự thoát ra với mã lỗi khác 0, nhưng khi bất kỳ lệnh nào chạy bởi trình bao đó không thuộc điều kiện (như trong if cmd
hoặc cmd ||
) thoát với trạng thái thoát khác 0 .
Thực tiễn chung là chúng tôi xác định một trình xử lý bẫy để cung cấp thêm thông tin gỡ lỗi về dòng nào và nguyên nhân dẫn đến việc thoát. Hãy nhớ mã thoát của lệnh cuối cùng gây ra ERR
tín hiệu sẽ vẫn có sẵn tại thời điểm này.
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
}
và chúng tôi chỉ sử dụng trình xử lý này như bên dưới ở đầu tập lệnh không thành công
trap cleanup ERR
Đặt điều này lại với nhau trên một tập lệnh đơn giản có false
ở dòng 15, thông tin bạn sẽ nhận được là
error condition hit
exit code returned: 1
the command executing at the time of the error was: false
command present on line: 15
Nó trap
cũng cung cấp các tùy chọn không phân biệt lỗi để chỉ chạy dọn dẹp khi hoàn thành shell (ví dụ: thoát script shell của bạn), theo tín hiệu EXIT
. Bạn cũng có thể bẫy nhiều tín hiệu cùng một lúc. Danh sách các tín hiệu được hỗ trợ để bẫy có thể được tìm thấy trên trap.1p - Trang hướng dẫn sử dụng Linux
Một điều khác cần lưu ý là phải hiểu rằng không có phương pháp nào được cung cấp hoạt động nếu bạn đang xử lý các trình bao con có liên quan đến trường hợp đó, bạn có thể cần thêm xử lý lỗi của riêng mình.
Trên một sub-shell với set -e
sẽ không hoạt động. Các false
bị hạn chế đến các tiểu vỏ và không bao giờ được tuyên truyền để các vỏ mẹ. Để thực hiện xử lý lỗi ở đây, hãy thêm logic của riêng bạn để làm(false) || false
set -e
(false)
echo survived
Điều tương tự cũng xảy ra với trap
. Logic bên dưới sẽ không hoạt động vì những lý do được đề cập ở trên.
trap 'echo error' ERR
(false)