วิธีตรวจสอบสถานะการออกโดยใช้คำสั่ง if


255

ฉันสงสัยว่าสิ่งใดจะเป็นวิธีที่ดีที่สุดในการตรวจสอบสถานะการออกในคำสั่ง if เพื่อสะท้อนผลลัพธ์เฉพาะ

ฉันคิดว่ามันเป็น

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

ปัญหาที่ฉันยังมีคือคำสั่ง exit อยู่ก่อนคำสั่ง if เพียงเพราะต้องมีรหัสการออกนั้น นอกจากนี้ฉันรู้ว่าฉันกำลังทำอะไรผิดพลาดเพราะทางออกจะเห็นได้ชัดว่าออกจากโปรแกรม


3
Plaese โพสต์สคริปต์ที่สมบูรณ์ของคุณ (หรืออย่างน้อยก็ขอบเขตที่กว้างขึ้น) อย่างนี้ดูเหมือนจะดี
RedX

5
หากคุณต้องการใช้รหัสออกจากการเรียกใช้โปรแกรมเฉพาะในสถานที่สองแห่งที่แตกต่างกันคุณจำเป็นต้องเก็บรักษาไว้ - บางสิ่งบางอย่างตามลำดับsome_program; rc=$?; if [ ${rc} -eq 1 ] .... fi ; exit ${rc}
twalberg

คำตอบ:


262

ทุกคำสั่งที่รันมีสถานะออก

การตรวจสอบนั้นดูสถานะการออกของคำสั่งที่เสร็จสิ้นล่าสุดก่อนที่บรรทัดนั้นจะทำงาน

ถ้าคุณต้องการของคุณสคริปต์เพื่อออกเมื่อทดสอบที่ผลตอบแทนจริง (คำสั่งก่อนหน้าล้มเหลว) แล้วคุณใส่exit 1(หรืออะไรก็ตาม) ภายในที่บล็อกหลังifecho

ที่ถูกกล่าวว่าหากคุณใช้คำสั่งและต้องการทดสอบผลลัพธ์โดยใช้สิ่งต่อไปนี้มักจะตรงไปข้างหน้ามากขึ้น

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

หรือหันไปรอบ ๆ ที่ใช้!สำหรับการปฏิเสธ

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

หมายเหตุว่าที่ค่าของความกังวลเหล่านั้นสิ่งที่รหัสข้อผิดพลาดคือ หากคุณรู้ว่าคุณสนใจเฉพาะรหัสข้อผิดพลาดเฉพาะคุณต้องตรวจสอบ$?ด้วยตนเอง


11
@ deadcell4 เมื่อหนึ่งในความต้องการที่จะยุติสคริปต์เชลล์ในความล้มเหลวของโปรแกรมสำนวนต่อไปนี้จะเป็นประโยชน์a_command || return 1
gboffi

10
@gboffi returnใช้งานได้เฉพาะในฟังก์ชั่นและสคริปต์ที่มา คุณต้องการexitสำหรับกรณีอื่น ๆ (ซึ่งมากเกินไปในฟังก์ชั่นและสคริปต์ที่มา) แต่ใช่ว่าเป็นรูปแบบที่เหมาะสมหากคุณไม่ต้องการการล้างข้อมูลหรือส่งออกเพิ่มเติม
Etan Reisner

1
ฉันต้องบอกว่าdashเชลล์เริ่มต้นที่ไม่ต้องมีการโต้ตอบในการแจกแจงลินุกซ์ที่ทันสมัยจำนวนมากไม่สนใจความแตกต่างระหว่างreturnและexitภายในของสคริปต์เชลล์ที่ดำเนินการ dashออกจากสคริปต์แม้ว่าฉันจะใช้returnมันก็ตาม
gboffi

ตรรกะเบื้องหลังการตรวจสอบสองครั้งล่าสุดคืออะไร ดูเหมือนว่าเคาน์เตอร์ใช้งานง่ายว่าเงื่อนไขif <command>ผ่านหากรหัสออกเป็น 0 ในภาษาอื่น ๆ มันจะเป็นวิธีอื่น ๆ รอบ ๆ
4254

3
หมายเหตุสำคัญ: วิธีนี้ใช้ไม่ได้กับท่อ if ! some_command | some_other_commandจะไม่สนใจสถานะของ some_command วิธีแก้ปัญหาคำสั่งสองคำสั่งส่วนใหญ่คือset -o pipefail(อาจเปลี่ยนการทำงานในส่วนอื่น ๆ ของโปรแกรมของคุณ) หรือเพื่อย้ายifคำสั่งไปif [[ ${PIPESTATUS[0]} -ne 0 ]]เป็นคำสั่งติดตามผลแยกต่างหาก (น่าเกลียด แต่ทำงานได้) หากคุณกำลังใช้อยู่set -eคุณจะต้องเพิ่ม|| trueที่ส่วนท้ายของไพพ์เมื่อใช้โซลูชันที่สองนับตั้งแต่การลบไพพ์ออกจากโฟลว์ควบคุมที่เสนอโดยifมิฉะนั้นจะทำให้ออกทันที
Alex Jansen

186

โปรดทราบว่ารหัสออก! = 0 ใช้เพื่อรายงานข้อผิดพลาด ดังนั้นจะดีกว่าที่จะทำ:

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

แทน

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

คุณต้องทดสอบ retVal เพราะ $? หลังจากการกำหนด retVal ไม่ใช่ค่าส่งคืนจากคำสั่งของคุณ
anr78

ไม่ได้จริงๆ: mywiki.wooledge.org/BashFAQ/002 - อย่างไรก็ตามฉันยอมรับว่าการแก้ไขช่วยให้อ่านง่ายขึ้น
Oo.oO

1
เพิ่งพบโพสต์นี้ที่อธิบายว่าstackoverflow.com/questions/20157938/…
anr78

dnf check-updateส่งคืน 0 (ไม่มีการอัปเดต), 100 (มีให้อัปเดต) หรือ 1 (ข้อผิดพลาด)
jww

1
@ jww - ก็ไม่ใช่ความคิดที่ดีที่จะต่อต้านการประชุม ( gnu.org/software/bash/manual/html_node/Exit-Status.html ) แต่ก็ไม่มีอะไรจะป้องกันได้ หากdnfนักพัฒนาเลือกวิธีนี้เป็นทางเลือกของพวกเขา แต่ถึงกระนั้นทางเลือกของพวกเขาก็ไม่ได้ทำให้ส
เป็ค

44

$?เป็นพารามิเตอร์ที่เหมือนกัน exitคุณสามารถบันทึกค่าในการใช้ท้ายที่สุดก่อนที่โทร

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

29

ทางเลือกที่ชัดเจน ifแถลง

น้อยที่สุด:

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

สมบูรณ์:

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

13

เพียงเพิ่มคำตอบที่เป็นประโยชน์และมีรายละเอียด:

หากคุณต้องตรวจสอบรหัสออกอย่างชัดเจนจะเป็นการดีกว่าถ้าใช้ตัวดำเนินการทางคณิตศาสตร์(( ... ))วิธีนี้:

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

หรือใช้caseคำสั่ง:

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

คำตอบที่เกี่ยวข้องเกี่ยวกับการจัดการข้อผิดพลาดใน Bash:

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.