Tôi đang quan sát một số hành vi kỳ lạ khi sử dụng set -e
( errexit
), set -u
( nounset
) cùng với bẫy ERR và EXIT. Chúng có vẻ liên quan, vì vậy đặt chúng vào một câu hỏi có vẻ hợp lý.
1) set -u
không kích hoạt bẫy ERR
Mã số:
#!/bin/bash trap 'echo "ERR (rc: $?)"' ERR set -u echo ${UNSET_VAR}
- Dự kiến: Bẫy ERR được gọi, RC! = 0
- Thực tế: Bẫy ERR không được gọi, RC == 1
- Lưu ý:
set -e
không thay đổi kết quả
2) Sử dụng set -eu
mã thoát trong bẫy EXIT là 0 thay vì 1
Mã số:
#!/bin/bash trap 'echo "EXIT (rc: $?)"' EXIT set -eu echo ${UNSET_VAR}
- Dự kiến: Bẫy EXIT được gọi, RC == 1
- Thực tế: Bẫy EXIT được gọi, RC == 0
- Lưu ý: Khi sử dụng
set +e
, RC == 1. Bẫy EXIT trả về RC thích hợp khi bất kỳ lệnh nào khác đưa ra lỗi. - Chỉnh sửa: Có một bài viết SO về chủ đề này với một bình luận thú vị cho thấy rằng điều này có thể liên quan đến phiên bản Bash đang được sử dụng. Thử nghiệm đoạn mã này với Bash 4.3.11 cho kết quả RC = 1, vì vậy điều đó tốt hơn. Thật không may, việc nâng cấp Bash (từ 3.2.51) trên tất cả các máy chủ hiện tại là không thể, vì vậy chúng tôi phải đưa ra một số giải pháp khác.
Bất cứ ai có thể giải thích một trong những hành vi này?
Tìm kiếm các chủ đề này không thành công lắm, điều này khá đáng ngạc nhiên với số lượng bài đăng trên các cài đặt và bẫy của Bash. Có một chủ đề diễn đàn , mặc dù, nhưng kết luận là không hài lòng.
set -e
và set -u
cả hai đều được thiết kế đặc biệt để tiêu diệt một lớp vỏ kịch bản. Sử dụng chúng trong các điều kiện có thể kích hoạt ứng dụng của họ sẽ giết chết một lớp vỏ theo kịch bản. Không có xung quanh đó, ngoại trừ việc không sử dụng chúng, và thay vào đó để kiểm tra các điều kiện đó khi chúng áp dụng theo một chuỗi mã. Vì vậy, về cơ bản, bạn có thể viết mã shell tốt, hoặc bạn có thể sử dụng set -eu
.
-u
sẽ không kích hoạt bẫy ERR (đó là lỗi, vì vậy không nên kích hoạt bẫy) hoặc mã lỗi là 0 thay vì 1. cái sau dường như là một lỗi đã được sửa trong phiên bản sau, vì vậy đó là. Nhưng phần đầu tiên khá khó hiểu nếu bạn chưa nhận ra rằng lỗi trong đánh giá hệ vỏ (mở rộng tham số) và lỗi thực tế trong các lệnh dường như là hai điều khác nhau. Đối với giải pháp, như bạn đã đề xuất, hiện tôi đang cố gắng tránh -eu
và kiểm tra thủ công khi cần thiết.
(set -u; : $UNSET_VAR)
và tương tự. Loại công cụ này cũng có thể tốt - đôi khi bạn có thể bỏ rất nhiều thứ &&
: (set -e; mkdir dir; cd dir; touch dirfile)
, nếu bạn nhận được sự trôi dạt của tôi. Chỉ là những bối cảnh được kiểm soát - khi bạn đặt chúng làm tùy chọn toàn cầu, bạn sẽ mất kiểm soát và bị kiểm soát. Thường có những giải pháp hiệu quả hơn.
bash
đã phá vỡ tiêu chuẩn và bắt đầu đặt bẫy vào các mạng con. Cái bẫy được cho là sẽ được thực hiện trong cùng một môi trường từ khi quay trở lại, nhưngbash
đã không thực hiện được điều đó trong một lúc.