ออกจากสคริปต์ในข้อผิดพลาด


141

ฉันกำลังสร้างเชลล์สคริปต์ที่มีifฟังก์ชั่นเช่นนี้:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables
fi

...

ฉันต้องการให้การทำงานของสคริปต์เสร็จสิ้นหลังจากแสดงข้อความแสดงข้อผิดพลาด ฉันจะทำสิ่งนี้ได้อย่างไร

คำตอบ:


137

คุณกำลังมองหาexitอะไร?

นี่คือคู่มือทุบตีที่ดีที่สุด http://tldp.org/LDP/abs/html/

ในบริบท:

if jarsigner -verbose -keystore $keyst -keystore $pass $jar_file $kalias
then
    echo $jar_file signed sucessfully
else
    echo ERROR: Failed to sign $jar_file. Please recheck the variables 1>&2
    exit 1 # terminate and indicate error
fi

...


ลิงก์ทุบตีเหล่านั้นสุดยอดมาก! BashFAQ จะอยู่ในตำแหน่งที่ดีขึ้นในฐานะ BashRecipes
Pete Alvin

337

หากคุณใส่set -eสคริปต์สคริปต์จะยุติทันทีที่คำสั่งใด ๆ ที่อยู่ในนั้นล้มเหลว (เช่นทันทีที่คำสั่งใด ๆ ส่งคืนสถานะที่ไม่ใช่ศูนย์) สิ่งนี้ไม่อนุญาตให้คุณเขียนข้อความของคุณเอง แต่บ่อยครั้งที่ข้อความของคำสั่งที่ล้มเหลวนั้นเพียงพอแล้ว

ข้อดีของวิธีนี้คือมันเป็นไปโดยอัตโนมัติ: คุณไม่เสี่ยงต่อการลืมที่จะจัดการกับกรณีที่เกิดข้อผิดพลาด

คำสั่งที่มีสถานะมีการทดสอบโดยมีเงื่อนไข (เช่นif, &&หรือ||) ไม่ยุติสคริปต์ (มิฉะนั้นเงื่อนไขจะไม่มีจุดหมาย) command-that-may-fail || trueสำนวนสำหรับคำสั่งเป็นครั้งคราวที่มีความล้มเหลวไม่ได้เรื่องคือ นอกจากนี้คุณยังสามารถเปิดออกเพื่อเป็นส่วนหนึ่งของสคริปต์ด้วยset -eset +e


3
ตามmywiki.wooledge.org/BashFAQ/105 - คุณลักษณะนี้มีประวัติว่ามีความคลุมเครือและซับซ้อนในการพิจารณาว่ารหัสข้อผิดพลาดของคำสั่งใดทำให้เกิดการออกโดยอัตโนมัติ นอกจากนี้ "กฎเปลี่ยนจากเวอร์ชั่น Bash หนึ่งไปเป็นอีกรุ่นหนึ่งเนื่องจาก Bash พยายามติดตามคำจำกัดความ POSIX ที่ลื่นไหลอย่างมากของ 'ฟีเจอร์' นี้" ฉันเห็นด้วยกับ @Dennis Williamson และคำตอบที่ยอมรับของstackoverflow.com/questions/19622198/ … - ใช้กับดัก 'error_handler' ERR แม้ว่ามันจะเป็นกับดัก!
Bondolin

3
บ่อยครั้งที่ใช้การ-xตั้งค่าสถานะด้วยการ-eตั้งค่าสถานะเพียงพอของการติดตามที่โปรแกรมของคุณออก นั่นก็หมายความว่าผู้ใช้สคริปต์เป็นผู้พัฒนาเช่นกัน
Alex

ดี แต่ฉันคิดว่า OP จำเป็นต้องออกจากสคริปต์จากข้อยกเว้นที่กำหนดโดยตัวเอง
vdegenne

42

หากคุณต้องการที่จะสามารถที่จะจัดการกับข้อผิดพลาดแทนที่จะสุ่มสี่สุ่มห้าออกแทนการใช้set -eใช้trapในERRสัญญาณหลอก

#!/bin/bash
f () {
    errorCode=$? # save the exit code as the first thing done in the trap function
    echo "error $errorCode"
    echo "the command executing at the time of the error was"
    echo "$BASH_COMMAND"
    echo "on line ${BASH_LINENO[0]}"
    # do some error handling, cleanup, logging, notification
    # $BASH_COMMAND contains the command that was being executed at the time of the trap
    # ${BASH_LINENO[0]} contains the line number in the script of that command
    # exit the script or return to try again, etc.
    exit $errorCode  # or use some other value or do return instead
}
trap f ERR
# do some stuff
false # returns 1 so it triggers the trap
# maybe do some other stuff

กับดักอื่น ๆ ที่สามารถตั้งค่าที่จะจัดการกับสัญญาณอื่น ๆ รวมทั้งสัญญาณ Unix ปกติบวกสัญญาณทุบตีหลอกอื่น ๆและRETURNDEBUG


8

นี่คือวิธีที่จะทำ:

#!/bin/sh

abort()
{
    echo >&2 '
***************
*** ABORTED ***
***************
'
    echo "An error occurred. Exiting..." >&2
    exit 1
}

trap 'abort' 0

set -e

# Add your script below....
# If an error occurs, the abort() function will be called.
#----------------------------------------------------------
# ===> Your script goes here
# Done!
trap : 0

echo >&2 '
************
*** DONE *** 
************
'

ทำไมต้องทำข้อความถึง stderr
MattBianco

1
นี่เป็นวิธีปฏิบัติทั่วไปเพื่อให้คุณสามารถไพพ์เอาท์พุทสคริปต์ของคุณไปยัง stdout เพื่อให้กระบวนการอื่นสามารถทำได้โดยไม่ต้องมีข้อความข้อมูลอยู่ตรงกลาง
supercobra

2
อาจเป็นวิธีปฏิบัติที่เท่าเทียมกันโดยทั่วไปในการรักษาทุกสิ่งบน stderr เพื่อบ่งชี้ปัญหา
MattBianco

1
ในอดีต 'set -e' ใช้ได้กับฉันเสมอ แต่คืนนี้ฉันเจอกับสถานการณ์ในรูปอัลไพน์ Linux Docker ที่มันไม่มีผลอะไรเลย .. วิธีนี้ใช้ได้ผลสำหรับฉันและทำให้ฉันกลับมาทำงานด้วยมือ ชื่นชมมาก
synthesizerpatel

@supercobra การปฏิบัติทั่วไป? ที่ไหน?
Thorbjørn Ravn Andersen

-8

exit 1คือทั้งหมดที่คุณต้องการ นี่1คือโค้ดส่งคืนดังนั้นคุณสามารถเปลี่ยนได้หากคุณต้องการพูด1เพื่อให้หมายถึงการรันที่ประสบความสำเร็จและ-1หมายถึงความล้มเหลวหรืออะไรทำนองนั้น


13
ในยูนิกซ์ที่ประสบความสำเร็จอยู่เสมอ 0. นี้อาจช่วยให้เมื่อใช้testหรือหรือ&& ||
mouviciel

5
หากต้องการขยายความคิดเห็นของ mouviciel: ในเชลล์สคริปต์ 0 หมายถึงความสำเร็จเสมอและ 1 ถึง 255 หมายถึงความล้มเหลว -1 อยู่นอกช่วง (และมักจะมีผลเช่นเดียวกับ 255 ดังนั้นความล้มเหลวเช่น 1)
Gilles 'หยุดความชั่วร้าย'

@mouviciel, @Gilles: ขอบคุณสำหรับข้อมูลพิเศษ ไม่นานมานี้ตั้งแต่ฉันจัดการกับทุบตี
DGH

นี่เป็นตัวอย่างที่ดีของการใช้รหัสส่งคืนมิฉะนั้นจะเป็นคำตอบที่ดี
แบรดโคช์

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