Trạng thái thoát của đường ống là trạng thái thoát của lệnh bên phải. Trạng thái thoát của lệnh bên trái bị bỏ qua.
(Lưu ý rằng which lss | echo $?
không hiển thị điều này. Bạn sẽ chạy which lss | true; echo $?
để hiển thị điều này. Trong which lss | echo $?
, echo $?
báo cáo trạng thái của lệnh cuối cùng trước đường ống này.)
Lý do shell hoạt động theo cách này là có một kịch bản khá phổ biến trong đó một lỗi ở phía bên trái nên được bỏ qua. Nếu phía bên phải thoát (hoặc nói chung là đóng đầu vào tiêu chuẩn của nó) trong khi phía bên trái vẫn đang viết, thì phía bên trái nhận được tín hiệu SIGPIPE. Trong trường hợp này, thường không có gì sai: phía bên tay phải không quan tâm đến dữ liệu; nếu vai trò của phía bên trái chỉ là để tạo ra dữ liệu này thì nó có thể dừng lại.
Tuy nhiên, nếu phía bên trái chết vì một số lý do khác ngoài SIGPIPE hoặc nếu công việc của phía bên trái không chỉ tạo ra dữ liệu trên đầu ra tiêu chuẩn, thì lỗi ở phía bên trái là lỗi chính hãng nên được báo cáo.
Trong sh đơn giản, giải pháp duy nhất là sử dụng một đường ống có tên.
set -e
mkfifo p
command1 >p & pid1=$!
command2 <p
wait $pid1
Trong ksh, bash và zsh, bạn có thể ra lệnh cho shell thực hiện một lối thoát đường ống với trạng thái khác 0 nếu bất kỳ thành phần nào của đường ống thoát ra với trạng thái khác. Bạn cần đặt pipefail
tùy chọn:
- ksh:
set -o pipefail
- bash:
shopt -s pipefail
- zsh:
setopt pipefail
(hoặc setopt pipe_fail
)
Trong mksh, bash và zsh, bạn có thể nhận trạng thái của mọi thành phần của đường ống bằng cách sử dụng biến PIPESTATUS
(bash, mksh) hoặc pipestatus
(zsh), là một mảng chứa trạng thái của tất cả các lệnh trong đường ống cuối cùng (tổng quát hóa của $?
).
which lss | echo $?
,echo
được bắt đầu trước khiwhich
đã thoát; Shell tạo dòng lệnh choecho
không có cách nào có thể biết trạng thái thoátwhich
sau này sẽ là gì.