2014-06-27 13 views
6

Trong tập lệnh shell được thực hiện, tôi có thể hủy bỏ lỗi bằng cách sử dụng set -e.Bash: dừng khi gặp lỗi trong tập lệnh có nguồn gốc

Trong tập lệnh có nguồn gốc, tuy nhiên, sử dụng set -e sẽ giết vỏ gốc nếu lệnh sau thoát khỏi trạng thái lỗi.

source set_e.sh 
./exit_1.sh 
# shell dies 

Một giải pháp tầm thường sẽ được set +e ở phần cuối của kịch bản, nhưng điều này sẽ phá vỡ của cha mẹ set -e nếu được sử dụng (mà rất có thể xảy ra nếu một người nào đó kết thúc tốt đẹp kịch bản của tôi trong tương lai).

Làm cách nào để tôi có thể nhận chức năng gỡ lỗi trên một tập lệnh có nguồn gốc?

+0

@BlueMoon Bài đăng của OP giải thích tại sao điều đó không hiệu quả. –

+0

Bạn không thể đặt bẫy thoát trong môi trường gọi điện và xử lý nó ở đó? –

Trả lời

0

Bạn có thể phát hiện bằng set -o nếu tùy chọn errexit được đặt ở đầu tập lệnh có nguồn gốc và khôi phục giá trị ban đầu ở cuối tập lệnh gốc.

2

Bạn có thể kiểm tra xem set -e đã được kích hoạt và có điều kiện cài đặt nó sau đó:

[[ $- == *e* ]] && state=-e || state=+e 
set -e 
yourcode 
set "$state" 

Lưu ý, tuy nhiên, set -e là buggy và các kịch bản không bao giờ nên phụ thuộc vào nó cho đúng đắn. Ví dụ, nếu ai đó lấy nguồn kịch bản của bạn trong một tuyên bố if, set -e có thể không còn hoạt động chính xác:

echo ' 
set -e 
ls file.that.doesnt.exist 
echo "Success" 
' > yourscript 

set -e 
if ! source yourscript 
then 
    echo "Initialization failed" 
fi 
echo "Done" 

sau đó set -e còn sẽ hủy bỏ vào thất bại trong yourscript trong bash 4.3.30:

ls: cannot access file.that.doesnt.exist: No such file or directory 
Success 
Done 

khi nó sẽ thoát toàn bộ tập lệnh trong bash 2, 3 và tối đa 4.2:

ls: cannot access file.that.doesnt.exist: No such file or directory 
+1

Phần thứ hai là gây hiểu nhầm - nếu 'yourscript' đặt' errexit', mã trình bao bọc thực sự sẽ hủy bỏ các lỗi bên trong nó (được thử nghiệm với bash 4.2.x). Điều này có vẻ phản trực giác so với việc sử dụng thường xuyên shell nếu-thì-else, nhưng nếu bạn tìm nguồn cung ứng mã không đáng tin cậy, kỳ vọng mà bạn sẽ bọc nó trong một subshell không có vẻ gì là không hợp lý. –

+1

@JosipRodin Tôi thấy rằng bash 2 và 3 đã hủy bỏ toàn bộ tập lệnh, nhưng trên 4.3.30 (1) -giả làm cho nó không bị hủy bỏ như mô tả. Thú vị khi biết rằng hành vi đã thay đổi rất nhiều. –

+0

Bắt tốt. Tôi nghĩ rằng hành vi hiện tại là phù hợp với lời khuyên chính - để sử dụng một subshell. Ví dụ, nếu bạn làm: 'set + e; (. yourscript); nếu [$? -ne 0]; sau đó echo "Khởi tạo thất bại"; fi' - kết quả là khá hợp lý. –

3

Thay đổi set -e đến return 0 (hoặc chọn số nguyên yêu thích của bạn thay vì 0). Bạn có thể nghĩ về nó như điều trị tập tin có nguồn gốc của bạn như là một chức năng. Ví dụ:

$ cat myreturn.sh 
#!/bin/bash 

let i=0 

while test "$i" -lt 10; do 

    echo "i $i" 
    if test "$i" -gt 5 ; then 
     return 5 
    fi 
    sleep 1 
    ((i+=1)) 

done 

return 4 

$ (. myreturn.sh) 
i 0 
i 1 
i 2 
i 3 
i 4 
i 5 
i 6 

$ echo $? 
5 
+0

Tại sao câu trả lời này không phải là câu trả lời đầu tiên? Cảm ơn nhiều!! – eplaut

4

Không thể. Tuy nhiên, bạn có thể chọn sử dụng danh mục phụ nếu bạn muốn:

(
    set -e 
    source another.sh 
) 

Chỉ có thể thay đổi môi trường tập lệnh gọi đó bằng tập lệnh được gọi.

Lưu ý: Điều quan trọng là phải tách riêng cả hai lệnh bằng dòng mới và không sử dụng dấu chấm phẩy.

2

Vâng, câu hỏi không phải là tái rất rõ ràng: những gì tác giả ban đầu muốn sau khi chặn các lỗi trong kịch bản có nguồn gốc, tuy nhiên, như là một điểm khởi đầu cho các giải pháp sau đây sẽ đủ:

Bạn có thể thiết lập một bẫy trên ERR và xử lý lỗi bên trong tập lệnh có nguồn gốc ở đó. Dưới đây là hai kịch bản: một kịch bản có tập lệnh có nguồn gốc sử dụng "set -e" và tập lệnh khác có tập lệnh nguồn gốc KHÔNG sử dụng "set -e".

Các kịch bản chính đang kêu gọi các kịch bản phổ thông với định nghĩa "thiết lập -e" và bắt một lỗi: đánh bắt

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

set -e 
echo 'Primary script' 
trap 'echo "Got an error from the secondary script"' ERR 
source secondary.sh 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
set -e 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
[galaxy => ~]$ 

Các kịch bản chính đang kêu gọi các kịch bản thứ mà không cần "đặt -e" và một lỗi:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

set -e 
echo 'Primary script' 
trap 'echo "Got an error from the secondary script"' ERR 
source secondary.sh 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached if sourced by primary.sh' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
[galaxy => ~]$ 

Như một phần thưởng: chặn một lỗi trong kịch bản có nguồn gốc và tiếp tục:

[galaxy => ~]$ cat primary.sh 
#!/bin/sh 

echo 'Primary script' 
i=0 
while [ $i = 0 ]; do 
    i=1 
    trap 'echo "Got an error from the secondary script"; break' ERR 
    source secondary.sh 
done 
trap - ERR 
echo 'Primary script exiting' 
[galaxy => ~]$ cat secondary.sh 
#!/bin/sh 

echo 'Secondary script' 
echo 'Secondary script generating an error' 
false 
echo 'Secondary script - should not be reached if sourced by primary.sh' 
[galaxy => ~]$ ./primary.sh 
Primary script 
Secondary script 
Secondary script generating an error 
Got an error from the secondary script 
Primary script exiting 
[galaxy => ~]$ 
Các vấn đề liên quan