Cách kiểm tra trạng thái thoát bằng câu lệnh if


255

Tôi đã tự hỏi điều gì sẽ là cách tốt nhất để kiểm tra trạng thái thoát trong câu lệnh if để lặp lại một đầu ra cụ thể.

Tôi đang nghĩ về nó

if [ $? -eq 1 ]
then
   echo "blah blah blah"
fi

Vấn đề tôi cũng gặp phải là câu lệnh exit nằm trước câu lệnh if đơn giản vì nó phải có mã thoát đó. Ngoài ra, tôi biết tôi đang làm gì đó sai vì lối ra rõ ràng sẽ thoát khỏi chương trình.


3
Plaese đăng kịch bản hoàn chỉnh của bạn (hoặc ít nhất là một phạm vi rộng hơn). Khác điều này có vẻ tốt.
RedX

5
Nếu bạn cần sử dụng mã thoát khỏi một số lời mời chương trình cụ thể ở hai nơi khác nhau, thì bạn cần giữ nó - một cái gì đó dọc theo dòngsome_program; rc=$?; if [ ${rc} -eq 1 ] .... fi ; exit ${rc}
twalberg

Câu trả lời:


262

Mỗi lệnh chạy có một trạng thái thoát.

Kiểm tra đó đang xem trạng thái thoát của lệnh đã hoàn thành gần đây nhất trước khi dòng đó chạy.

Nếu bạn muốn tập lệnh của mình thoát khi kiểm tra đó trả về true (lệnh trước đó không thành công) thì bạn đặt exit 1(hoặc bất cứ thứ gì) vào bên trong ifkhối đó sau echo.

Điều đó đang được nói nếu bạn đang chạy lệnh và muốn kiểm tra đầu ra của nó bằng cách sử dụng như sau thường đơn giản hơn.

if some_command; then
    echo command returned true
else
    echo command returned some error
fi

Hoặc để biến điều đó xung quanh sử dụng !cho phủ định

if ! some_command; then
    echo command returned some error
else
    echo command returned true
fi

Lưu ý rằng mặc dù không ai trong số những người quan tâm những gì mã lỗi là. Nếu bạn biết bạn chỉ quan tâm đến một mã lỗi cụ thể thì bạn cần kiểm tra $?thủ công.


11
@ deadcell4 Khi một người cần chấm dứt tập lệnh shell khi chương trình bị lỗi, thành ngữ sau đây rất hữu ícha_command || return 1
gboffi

10
@gboffi returnchỉ hoạt động trong một chức năng và một tập lệnh có nguồn gốc. Bạn cần exitcho trường hợp khác (mà quá nhiều trong một chức năng và một tập lệnh có nguồn gốc). Nhưng vâng, đó chắc chắn là một mô hình hợp lý nếu bạn không cần bất kỳ hoạt động dọn dẹp cụ thể hoặc đầu ra thêm nào.
Etan Reisner

1
Tôi phải nói rằng dash, trình bao không tương tác mặc định trong nhiều bản phân phối linux hiện đại, không quan tâm đến sự khác biệt giữa returnexitbên trong các tập lệnh shell được thực thi. dashthoát khỏi tập lệnh ngay cả khi tôi sử dụng returnnó.
gboffi

Logic đằng sau hai lần kiểm tra cuối là gì? Có vẻ như phản trực giác rằng điều kiện if <command>vượt qua nếu mã thoát là 0. Trong bất kỳ ngôn ngữ nào khác, nó sẽ là cách khác
sjw

3
LƯU Ý QUAN TRỌNG: Điều này sẽ không làm việc cho đường ống. if ! some_command | some_other_commandsẽ bỏ qua trạng thái của some_command. Hai cách giải quyết lệnh nhất là set -o pipefail(có thể thay đổi chức năng trong các phần khác của chương trình của bạn) hoặc để di chuyển ifcâu lệnh thành if [[ ${PIPESTATUS[0]} -ne 0 ]]một lệnh theo dõi riêng biệt (xấu, nhưng có chức năng). Nếu bạn đang sử dụng set -ethì bạn cũng sẽ muốn thêm || truevào cuối đường ống khi sử dụng giải pháp thứ hai kể từ khi tháo đường ống khỏi luồng điều khiển được cung cấp bởi ifnếu không sẽ khiến nó thoát ngay lập tức.
Alex Jansen

186

Lưu ý rằng mã thoát! = 0 được sử dụng để báo cáo lỗi. Vì vậy, tốt hơn là làm:

retVal=$?
if [ $retVal -ne 0 ]; then
    echo "Error"
fi
exit $retVal

thay vì

# will fail for error codes > 1
retVal=$?
if [ $retVal -eq 1 ]; then
    echo "Error"
fi
exit $retVal

Bạn phải kiểm tra trên retVal, vì $? sau khi gán retVal không phải là giá trị trả về từ lệnh của bạn.
anr78

Không thực sự: mywiki.wooledge.org/BashFAQ/002 - tuy nhiên, tôi đồng ý rằng chỉnh sửa giúp cải thiện khả năng đọc.
Oo.oO

1
Chỉ cần tìm thấy bài đăng này giải thích nó stackoverflow.com/questions/20157938/ từ
anr78

dnf check-updatetrả về 0 (không cập nhật), 100 (có sẵn cập nhật) hoặc 1 (lỗi).
19 lúc 22 giờ 37 phút

1
@jww - tốt, đó không phải là một ý tưởng hay để đi ngược lại quy ước ( gnu.org/software/bash/manual/html_node/Exit-Status.html ). Nhưng, tốt, không có gì để ngăn chặn điều đó. Nếu các dnfnhà phát triển đã chọn cách này, đó là lựa chọn của họ. Tuy nhiên, sự lựa chọn của họ không làm cho đặc tả bị phá vỡ :)
Oo.oO

44

$?là một tham số như bất kỳ khác. Bạn có thể lưu giá trị của nó để sử dụng trước khi gọi exit.

exit_status=$?
if [ $exit_status -eq 1 ]; then
    echo "blah blah blah"
fi
exit $exit_status

29

Thay thế cho tường minh if tuyên bố

Tối thiểu:

test $? -eq 0 || echo "something bad happened"

Hoàn thành:

EXITCODE=$?
test $EXITCODE -eq 0 && echo "something good happened" || echo "something bad happened"; 
exit $EXITCODE

13

Chỉ để thêm vào câu trả lời hữu ích và chi tiết :

Nếu bạn phải kiểm tra mã thoát một cách rõ ràng, tốt hơn là sử dụng toán tử số học (( ... )), theo cách này:

run_some_command
(($? != 0)) && { printf '%s\n' "Command exited with non-zero"; exit 1; }

Hoặc, sử dụng một casetuyên bố:

run_some_command; ec=$?  # grab the exit code into a variable so that it can
                         # be reused later, without the fear of being overwritten
case $ec in
    0) ;;
    1) printf '%s\n' "Command exited with non-zero"; exit 1;;
    *) do_something_else;;
esac

Câu trả lời liên quan về xử lý lỗi trong Bash:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.