ทำไมรูปแบบ“ คำสั่ง || จริง” มีประโยชน์หรือไม่


79

ขณะนี้ฉันกำลังสำรวจแพ็คเกจ Debian และฉันได้อ่านตัวอย่างโค้ดแล้ว และในทุกบรรทัดตัวอย่างpostinstสคริปต์เป็นรูปแบบ

some command || true
another command || true

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


5
FYI ||:เป็นอีกวิธีหนึ่งในการเขียนแบบนี้ ( :เป็นอีกรายการในตาราง builtin ที่ชี้ไปที่true- แต่รับประกันว่าจะเป็น builtin แม้กลับไปที่ Bourne ที่กล่าวว่าสำหรับ POSIX sh trueก็รับประกันได้ว่าจะเป็น builtin - ดังนั้นจึงเป็น ความทนทานยิ่งกว่าประสิทธิภาพในเวลาที่ทันสมัยแม้ในระยะไกล)
Charles Duffy

คำตอบ:


151

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

ในกรณีที่คำสั่งในสคริปต์ได้รับอนุญาตให้ล้มเหลวการเพิ่ม|| trueให้แน่ใจว่าคำสั่งผสมที่เกิดขึ้นจะออกจากสถานะศูนย์เสมอดังนั้นสคริปต์จะไม่ยกเลิก ตัวอย่างเช่นการลบไดเรกทอรีไม่ควรเป็นข้อผิดพลาดร้ายแรง (ป้องกันไม่ให้แพคเกจถูกลบ); ดังนั้นเราจะใช้

rmdir ... || true

เนื่องจากrmdirไม่มีตัวเลือกที่จะบอกให้ละเว้นข้อผิดพลาด


4
ดีโดยไม่set -eต้องมีการไม่มี|| trueเลยผมคิดว่ามันสำคัญที่จะให้บริบท หากคุณสังเกตเห็นสิ่งผิดปกติใน POWER ฉันขอแนะนำให้คุณใช้ไฟล์บั๊ก ( reportbug)!
Stephen Kitt

16
@MichaelFelt ที่จริงแล้วset -eไม่เพียง แต่เป็น "การประชุมแบบเดเบียน" เท่านั้น แต่รูปแบบการเขียนโปรแกรมที่ดีควรใช้เสมอ ดู. เช่นdavidpashley.com/articles/writing-robust-shell-scripts
kay

2
ตามคำถามที่นี่ - เหตุใดจึงใช้|| trueset -e เป็นบริบทที่เป็นไปได้และเป็นไปได้มากที่สุด ฉันคำนับคำตอบนี้! แม้ว่าตามจริงแล้วมันจะมีประโยชน์ทุกครั้งที่สถานะการออกถือว่าไม่เกี่ยวข้องและ (ตามที่คุณเพิ่มลิงก์บทความ) ฉันไม่ได้ใช้สถานะออกเป็นส่วนหนึ่งของการควบคุมสคริปต์ของฉัน ฉันเห็นอรรถประโยชน์ (ในset -e) แต่จะไม่ไปไกลเท่าที่บทความทำและพูดว่า "ทุกสคริปต์ที่คุณเขียนควรมี set -e ที่ด้านบน" มันเป็นรูปแบบของการเขียนโปรแกรม "เสมอ | ทุก ๆ " รวมถึงกับดักของตัวเอง - aka - แน่นอนว่า: โซลูชั่นการ์ดป่าจะALWAYSย้อนกลับมาในที่สุด aka - ไม่มีการขี่ฟรี
Michael Felt

1
@Kay นั่นเป็นมุมมองที่ได้รับความนิยมในปัจจุบัน แต่ท้ายที่สุดก็ติดอยู่กับข้อสันนิษฐานมากมายซึ่ง จำกัด การพกพาของสคริปต์ มีความไม่สอดคล้องกันในอดีตกับset -eพฤติกรรม มันอาจไม่สำคัญสำหรับคุณหากเป้าหมายเดียวของคุณคือbashและเชลล์ที่ค่อนข้างใหม่ล่าสุดที่อาศัยอยู่/bin/shแต่สถานการณ์นั้นมีความเหมาะสมมากขึ้นเมื่อคุณต้องการสนับสนุนเชลล์ / ระบบเก่า
mtraceur

2
@StephenKitt แน่นอน มีหน้าset -eอย่างละเอียดมากที่บันทึกพฤติกรรมของกระสุนที่แตกต่างกันโดย Sven Mascheckแต่หน้านี้ยังจัดทำเอกสารเกี่ยวกับเปลือกหอยประวัติศาสตร์ / โบราณจำนวนมากที่ไม่เกี่ยวข้องในวันนี้ นอกจากนี้ยังมีสองหน้านี้ที่มีความสำคัญที่แคบลง (ค้นหา "set -e"): หน้า "lintsh" , เอกสารเชลล์แบบพกพาของ autoconf -> ข้อ จำกัด ของหน้าย่อย
Builtins

32

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

Rephrased: มันปิดบังสถานะข้อผิดพลาดของคำสั่งก่อนหน้า

michael@x071:[/usr/sbin]cat /tmp/false.sh
#!/bin/sh
false

michael@x071:[/usr/sbin]cat /tmp/true.sh 
#!/bin/sh
false || true

michael@x071:[/usr/sbin]sh /tmp/false.sh; echo $?
1
michael@x071:[/usr/sbin]sh /tmp/true.sh; echo $? 
0

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

4
set -e หมายความว่าสคริปต์จะยุติทันทีเมื่อผลตอบแทนที่ไม่ใช่ศูนย์ คุณอาจในจุดที่แปลไม่ต้องการที่เกิดขึ้น!
rackandboneman

ฉันเป็นคนเรียบง่าย - และสำหรับฉันเหตุผลเดียวที่ปิดบังสถานะข้อผิดพลาดคือเพราะมันคือ "ในทาง" ชุด -e ทำให้เกิดข้อผิดพลาด "ในทาง" ถ้าก่อนที่คุณไม่ได้ดูแล ฉันชอบการอภิปรายเพราะฉันเห็นว่าเป็นวิธีที่ดีในการช่วยแก้ปัญหาสคริปต์ของฉันและเขียนตรรกะเพิ่มเติมเพื่อตอบสนองต่อข้อผิดพลาด (เช่น | | พิมพ์ - "xxx มีอยู่ไม่ใช่ศูนย์ที่นี่" มีแนวโน้มมากขึ้นแม้ว่าฉันจะ ฟังก์ชัน shell 'fatal' และฉันมี "some || fatal" unhappy me "imho สคริปต์ควรรายงานสถานะที่ล้มเหลวหรือไม่สนใจ -e plus || true คือการปกปิดข้อผิดพลาดถ้านั่นคือสิ่งที่ฉันต้องการ - ปรับ ถ้าไม่ฉันพลาดข้อผิดพลาด
Michael Felt

สิ่งที่ฉันต้องถามตัวเองคือ: || จริง - crutch การเข้ารหัส (วิธีขี้เกียจที่จะแก้ไขข้อผิดพลาดที่ผ่านมาฉันไม่ต้องการจัดการในตอนนี้เครื่องมือ debug (-e แต่ไม่ใช่ || จริง) หรือเพียงแค่ความเชื่อของใครบางคนเกี่ยวกับการปฏิบัติที่ดีในการเข้ารหัส - ฉันเห็นว่ามันเป็นคุณสมบัติ - มีประโยชน์ที่อาจเกิดขึ้นฉันไม่เห็นว่ามันเป็นไม้เท้าวิเศษในการรักษาทั้งหมดในระยะสั้น - เช่นเดียวกับความงามที่อยู่ในสายตาของคนดู - set -eและ|| trueยูทิลิตี้จะถูกกำหนดโดยลักษณะและเป้าหมายของ โปรแกรมเมอร์
Michael Felt

6
@MichaelFelt พิจารณา: git remote remove foo || true git remote add foo http://blah- เราต้องการละเว้นข้อผิดพลาดหากไม่มีรีโมท
user253751
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.