Các set -e
là vấn đề ở đây: -e
có nghĩa là "lối ra nếu có điều gì không", trong đó "thất bại" được định nghĩa là "lối thoát hiểm khác không".
Chúng tôi nhìn thấy trong đầu ra, như một vài dòng cuối cùng:
+ check_run .gitmodules 'git submodule update --init --recursive'
+ echo ''
+ grep --quiet .gitmodules
(và sau đó không có gì khác). Tập lệnh đã thoát sau grep --quiet
.
Đây là định nghĩa thực tế của check_run
:
check_run() {
echo "$changed_files" | grep --quiet "$1" && eval "$2"
}
này phân tích như left && right
nơi trái là echo ... | grep ...
và đúng là eval "$2"
.
Chúng tôi thấy rằng phần bên trái chạy và phần bên phải không. Dưới đây là nơi chúng tôi cần biết điều gì đó về shell: ngay cả với -e
được đặt, chúng không ngay lập tức thoát nếu có lỗi nào đó, miễn là một cái gì đó là một phần của thử nghiệm. Vì vậy, đây không phải là vấn đề ngay lập tức.
Nhưng nó vẫn là vấn đề, bởi vì left && right
có, như trạng thái thoát, trạng thái thoát của điều cuối cùng nó chạy. Điều cuối cùng nó chạy là đường ống bên trái, là echo ... | grep ...
. Trạng thái thoát của đường ống là trạng thái thoát của thành phần cuối cùng của nó, tức là, grep
. Các grep thoát số không nếu nó tìm thấy chuỗi (và với --quiet
, cũng ngăn chặn đầu ra của nó), 1 nếu không, và 2 trên các lỗi chung, do đó trạng thái thoát là 1.
Do đó, trạng thái thoát của left && right
là cũng 1.
Do đó, kể từ khi -e
có hiệu lực, trình bao đã thoát!
Việc chữa bệnh là để tránh -e
(nhưng điều này có nghĩa là nếu có lỗi khác không mong muốn, vỏ cày, vì vậy điều này có thể hơi nguy hiểm) hoặc để đảm bảo rằng left && right
không làm cho thoát khỏi trình bao.
Có một cách đơn giản để làm sau này: thay thế left && right
với if left; then right; fi
:
if echo "$changed_files" | grep --quiet "$1"; then
eval "$2"
fi
Lưu ý rằng nếu eval "$2"
thất bại, vỏ sẽ vẫn thoát.
Có cách khác và hơi phức tạp để thực hiện việc này với hiệu ứng khác: thay thế left && right
bằng left && right || true
. Các "và" biểu hiện liên kết chặt chẽ hơn, vì vậy điều này có nghĩa:
- Đánh giá trái
- Nếu mà thành công (thoát zero), đánh giá đúng
- Nếu
&&
thất bại (hoặc trái thoát nonzero hoặc phải được chạy và phải thoát khỏi không đồng bộ), đánh giá phần || true
, thoát khỏi 0.
Do đó:
echo "$changed_files" | grep --quiet "$1" && eval "$2" || true
luôn thoát 0, eval
-ing "$2"
khi và chỉ khi ở phía bên trái bị lỗi (không tìm thấy grepped-cho expression).
Nếu bạn muốn check_run
để cày ngay cả khi eval "$2"
không thành công, hãy sử dụng phiên bản thứ hai (|| true
). Nếu bạn muốn check_run
để dừng (và có toàn bộ lối thoát) dưới -e
nếu eval "$2"
không thành công, hãy sử dụng phiên bản đầu tiên (if ...; then
).
Thực sự cổ 4BSD /bin/sh
, rất lâu trước khi nó đã đi mã nguồn mở, có một lỗi: -e
sẽ làm cho lối ra vỏ trong những trường hợp này. (Tôi nghĩ rằng tôi đã cố định bản thân mình vào một thời điểm, nhưng khi 4BSD chuyển sang một sh mới, không dựa trên mã gốc của Steve Bourne, thì lỗi đó không có ở đó chút nào.)
Trong bash, bạn có thể kiểm soát điều này chi tiết hơn. Cụ thể, bạn có thể nhận được trạng thái mỗi thành phần của một đường ống trong biến mảng $PIPESTATUS
.
có thể chỉ định đường dẫn đầy đủ đến nhị phân 'npm'? – t0mm13b
@ t0mm13b nếu bạn nhìn vào hình ảnh bạn có thể thấy rằng nó thậm chí không bao giờ được vào dòng với npm nhưng thay vì thất bại trong/sau grep. Đó là lý do tại sao tôi bao gồm các dòng echo – jth41
ngay cả với grep, bao gồm một đường dẫn đầy đủ đến bất kỳ nhị phân là tốt, tại sao không echo mã lỗi '$?' Của lệnh thực hiện cuối cùng. – t0mm13b