นี่เป็นคำถามเก่า แต่ไม่มีคำตอบใดในที่นี้ที่กล่าวถึงการใช้set -e
aka set -o errexit
ในสคริปต์การจัดการแพ็คเกจ Debian การใช้ตัวเลือกนี้มีผลบังคับใช้ในสคริปต์เหล่านี้ตามนโยบายของเดเบียน เห็นได้ชัดว่ามีเจตนาที่จะหลีกเลี่ยงความเป็นไปได้ของเงื่อนไขข้อผิดพลาดที่ไม่สามารถจัดการได้
สิ่งนี้หมายความว่าในทางปฏิบัติคือคุณต้องเข้าใจภายใต้เงื่อนไขที่คำสั่งที่คุณเรียกใช้อาจส่งคืนข้อผิดพลาดและจัดการข้อผิดพลาดเหล่านั้นอย่างชัดเจน
gotchas ทั่วไปเป็นเช่นdiff
(ส่งกลับข้อผิดพลาดเมื่อมีความแตกต่าง) และgrep
(กลับข้อผิดพลาดเมื่อไม่มีการแข่งขัน) คุณสามารถหลีกเลี่ยงข้อผิดพลาดด้วยการจัดการที่ชัดเจน:
diff this that ||
echo "$0: there was a difference" >&2
grep cat food ||
echo "$0: no cat in the food" >&2
(โปรดสังเกตด้วยว่าเราใส่ใจที่จะรวมชื่อสคริปต์ปัจจุบันไว้ในข้อความอย่างไรและเขียนข้อความวินิจฉัยลงในข้อผิดพลาดมาตรฐานแทนที่จะเป็นเอาต์พุตมาตรฐาน)
หากไม่มีการจัดการที่ชัดเจนมีความจำเป็นหรือมีประโยชน์จริงๆอย่าทำอะไรเลย:
diff this that || true
grep cat food || :
(การใช้:
คำสั่ง no-op ของเชลล์ค่อนข้างคลุมเครือเล็กน้อย แต่เห็นได้ทั่วไป)
เพียงเพื่อย้ำ
something || other
เป็นการจดชวเลข
if something; then
: nothing
else
other
fi
นั่นคือเราother
ควรบอกว่าควรจะทำงานถ้าหากsomething
ล้มเหลว คำสั่ง long flow if
(และคำสั่งการควบคุมการไหลของเชลล์อื่น ๆ เช่นwhile
, until
) ก็เป็นวิธีที่ถูกต้องในการจัดการข้อผิดพลาด (แน่นอน, ถ้าไม่ใช่, เชลล์สคริปต์ด้วยset -e
ไม่สามารถมีคำสั่งการควบคุมการไหล!)
และเพื่อให้ชัดเจนในกรณีที่ไม่มีตัวจัดการเช่นนี้set -e
จะทำให้สคริปต์ทั้งหมดล้มเหลวทันทีด้วยข้อผิดพลาดหากdiff
พบความแตกต่างหรือหากgrep
ไม่พบคู่ที่ตรงกัน
ในทางกลับกันบางคำสั่งจะไม่สร้างสถานะการออกจากข้อผิดพลาดเมื่อคุณต้องการ คำสั่งที่มีปัญหาโดยทั่วไปคือfind
(สถานะออกไม่ได้สะท้อนว่าพบไฟล์จริงหรือไม่) และsed
(สถานะออกจะไม่เปิดเผยว่าสคริปต์ได้รับอินพุตใด ๆ หรือดำเนินการคำสั่งใด ๆ สำเร็จจริง ๆ หรือไม่ ตัวป้องกันอย่างง่ายในบางสถานการณ์คือการไพพ์ไปยังคำสั่งซึ่งจะกรีดร้องหากไม่มีเอาต์พุต:
find things | grep .
sed -e 's/o/me/' stuff | grep ^
ควรสังเกตว่าสถานะการออกของไปป์ไลน์เป็นสถานะออกของคำสั่งสุดท้ายในไปป์ไลน์นั้น ดังนั้นคำสั่งข้างต้นจะปกปิดสถานะของfind
และsed
โดยสมบูรณ์และบอกเพียงว่าคุณgrep
ประสบความสำเร็จในที่สุด
(แน่นอนว่า Bash มีset -o pipefail
แต่สคริปต์แพคเกจ Debian ไม่สามารถใช้คุณสมบัติ Bash ได้นโยบายกำหนดให้ใช้ POSIX sh
สำหรับสคริปต์เหล่านี้อย่างแน่นหนาแม้ว่าจะไม่ใช่กรณีนี้เสมอไป)
ในหลาย ๆ สถานการณ์นี่เป็นสิ่งที่ต้องระวังเมื่อทำการเข้ารหัสแบบป้องกัน บางครั้งคุณต้องผ่านไฟล์ชั่วคราวเพื่อให้คุณสามารถดูว่าคำสั่งที่สร้างเอาต์พุตนั้นเสร็จสมบูรณ์หรือไม่แม้ในกรณีที่สำนวนและความสะดวกสบายเป็นอย่างอื่นจะแนะนำให้คุณใช้เชลล์ไพพ์ไลน์