หากคุณไม่ต้องการให้คำสั่งที่สองดำเนินการต่อจนกว่าคำสั่งแรกจะสำเร็จคุณอาจต้องใช้ไฟล์ชั่วคราว รุ่นที่เรียบง่ายคือ:
tmp=${TMPDIR:-/tmp}/mine.$$
if ./a > $tmp.1
then
if ./b <$tmp.1 >$tmp.2
then
if ./c <$tmp.2
then : OK
else echo "./c failed" 1>&2
fi
else echo "./b failed" 1>&2
fi
else echo "./a failed" 1>&2
fi
rm -f $tmp.[12]
นอกจากนี้ยังสามารถย่อการเปลี่ยนเส้นทาง '1> & 2' '> & 2'; อย่างไรก็ตามเชลล์ MKS เวอร์ชันเก่าจัดการการเปลี่ยนเส้นทางข้อผิดพลาดโดยไม่ได้นำหน้า '1' ดังนั้นฉันจึงใช้สัญกรณ์ที่ชัดเจนเพื่อความน่าเชื่อถือสำหรับทุกวัย
ไฟล์นี้จะรั่วไหลหากคุณขัดจังหวะบางอย่าง การเขียนโปรแกรมเชลล์ป้องกันการระเบิด (มากหรือน้อย) ใช้:
tmp=${TMPDIR:-/tmp}/mine.$$
trap 'rm -f $tmp.[12]; exit 1' 0 1 2 3 13 15
...if statement as before...
rm -f $tmp.[12]
trap 0 1 2 3 13 15
บรรทัดกับดักแรกระบุว่า 'รันคำสั่ง' rm -f $tmp.[12]; exit 1
'เมื่อสัญญาณใด ๆ 1 SIGHUP, 2 SIGINT, 3 SIGQUIT, 13 SIGPIPE หรือ 15 SIGTERM เกิดขึ้นหรือ 0 (เมื่อเชลล์ออกด้วยเหตุผลใดก็ตาม) หากคุณกำลังเขียนเชลล์สคริปต์การดักจับขั้นสุดท้ายจะต้องลบกับดักที่ 0 เท่านั้นซึ่งเป็นกับดักทางออกของเชลล์ (คุณสามารถปล่อยสัญญาณอื่น ๆ ไว้ได้เนื่องจากกระบวนการกำลังจะยุติต่อไป)
ในไปป์ไลน์เดิมเป็นไปได้ที่ 'c' จะอ่านข้อมูลจาก 'b' ก่อนที่ 'a' จะเสร็จสิ้นซึ่งโดยปกติแล้วจะเป็นที่ต้องการ (เช่นให้หลายคอร์ทำงานเป็นต้น) ถ้า 'b' เป็นเฟส 'sort' ก็จะใช้ไม่ได้ - 'b' ต้องดูอินพุตทั้งหมดก่อนจึงจะสามารถสร้างเอาต์พุตใด ๆ ได้
หากคุณต้องการตรวจสอบว่าคำสั่งใดล้มเหลวคุณสามารถใช้:
(./a || echo "./a exited with $?" 1>&2) |
(./b || echo "./b exited with $?" 1>&2) |
(./c || echo "./c exited with $?" 1>&2)
นี่เป็นเรื่องง่ายและสมมาตร - เป็นเรื่องเล็กน้อยที่จะขยายไปยังท่อ 4 ส่วนหรือ N-part
การทดลองง่ายๆด้วย 'set -e' ไม่ได้ช่วยอะไร
&&|
ซึ่งหมายความว่า "ดำเนินการต่อท่อต่อเมื่อคำสั่งก่อนหน้านี้สำเร็จ" ฉันคิดว่าคุณอาจมี|||
ซึ่งจะหมายถึง "ดำเนินการต่อท่อหากคำสั่งก่อนหน้าล้มเหลว" (และอาจไพพ์ข้อความแสดงข้อผิดพลาดเช่น Bash 4's|&
)