Ngôn ngữ chính xác được sử dụng trong đặc tả UNIX đơn để mô tả ý nghĩa củaset -e
là:
Khi tùy chọn này được bật, nếu một lệnh đơn giản không thành công vì bất kỳ lý do nào được liệt kê trong Hậu quả của lỗi Shell hoặc trả về giá trị trạng thái thoát> 0 và không phải là [lệnh có điều kiện hoặc bị phủ định], thì shell sẽ thoát ngay lập tức.
Có một sự mơ hồ về những gì xảy ra khi một lệnh như vậy xảy ra trong một lớp con . Từ quan điểm thực tế, tất cả các lớp con có thể làm là thoát và trả lại trạng thái khác không cho vỏ cha. Liệu shell cha sẽ lần lượt thoát ra hay không phụ thuộc vào việc trạng thái khác không này có chuyển thành một lệnh đơn giản không thành công trong shell cha hay không.
Một trường hợp có vấn đề như vậy là trường hợp bạn gặp phải: trạng thái trả về khác không từ thay thế lệnh . Vì trạng thái này được bỏ qua, nó không khiến shell cha thoát ra. Như bạn đã phát hiện ra , một cách để đưa trạng thái thoát vào tài khoản là sử dụng thay thế lệnh trong một nhiệm vụ đơn giản : sau đó trạng thái thoát của nhiệm vụ là trạng thái thoát của thay thế lệnh cuối cùng trong (các) nhiệm vụ .
Lưu ý rằng điều này sẽ chỉ thực hiện như dự định nếu có một thay thế lệnh duy nhất, vì chỉ có trạng thái thay thế cuối cùng được tính đến. Ví dụ: lệnh sau thành công (cả theo tiêu chuẩn và trong mọi triển khai tôi đã thấy):
a=$(false)$(echo foo)
Một trường hợp khác để theo dõi là subshells rõ ràng : (somecommand)
. Theo cách giải thích ở trên, lớp con có thể trả về trạng thái khác không, nhưng vì đây không phải là một lệnh đơn giản trong vỏ cha, nên vỏ cha nên tiếp tục. Trong thực tế, tất cả các vỏ tôi biết làm cho cha mẹ trở lại vào thời điểm này. Mặc dù điều này hữu ích trong nhiều trường hợp như (cd /some/dir && somecommand)
sử dụng dấu ngoặc đơn để duy trì hoạt động như thư mục hiện tại thay đổi cục bộ, nhưng nó vi phạm đặc tả nếu set -e
bị tắt trong lớp con hoặc nếu lớp con trả về trạng thái khác không theo cách sẽ không chấm dứt nó, chẳng hạn như sử dụng !
trên một lệnh thực sự. Ví dụ: tất cả các lối ra tro, bash, pdksh, ksh93 và zsh mà không hiển thị foo
trên các ví dụ sau:
set -e; (set +e; false); echo "This should be displayed"
set -e; (! true); echo "This should be displayed"
Tuy nhiên, không có lệnh đơn giản đã thất bại trong khi set -e
có hiệu lực!
Một trường hợp có vấn đề thứ ba là các yếu tố trong một đường ống không cần thiết . Trong thực tế, tất cả các vỏ đều bỏ qua các lỗi của các phần tử của đường ống khác với phần tử cuối cùng và thể hiện một trong hai hành vi liên quan đến phần tử đường ống cuối cùng:
- ATT ksh và zsh, thực thi phần tử cuối cùng của đường ống trong shell cha, hoạt động như bình thường: nếu một lệnh đơn giản thất bại trong phần tử cuối cùng của đường ống, shell thực thi lệnh đó, xảy ra là shell cha, lối thoát hiểm
- Các shell khác xấp xỉ hành vi bằng cách thoát nếu phần tử cuối cùng của đường ống trả về trạng thái khác không.
Giống như trước đây, tắt set -e
hoặc sử dụng phủ định trong phần tử cuối cùng của đường ống làm cho nó trả về trạng thái khác không theo cách không nên chấm dứt lớp vỏ; shell khác với ATT ksh và zsh sau đó sẽ thoát.
pipefail
Tùy chọn của Bash làm cho một đường ống thoát ra ngay lập tức set -e
nếu bất kỳ phần tử nào của nó trả về trạng thái khác.
Lưu ý rằng như một sự phức tạp hơn nữa, bash sẽ tắt set -e
trong các lớp con trừ khi nó ở chế độ POSIX ( set -o posix
hoặc có POSIXLY_CORRECT
trong môi trường khi bash bắt đầu).
Tất cả những điều này cho thấy rằng đặc tả POSIX không may làm một công việc kém trong việc chỉ định -e
tùy chọn. May mắn thay, vỏ hiện có chủ yếu là phù hợp trong hành vi của họ.