เกิดอะไรขึ้น
เมื่อคุณกดCtrl+ Cที่SIGINT
สัญญาณจะถูกส่งมอบให้กับทั้งกลุ่มกระบวนการเบื้องหน้า ที่นี่มันถูกส่งไปยังทั้งfind
กระบวนการและกระบวนการเชลล์การเรียก find
ตอบสนองโดยออกจากทันทีและเชลล์ตอบสนองโดยการเรียกกับดัก
หากโค้ดในกับดักส่งคืน (เช่นไม่เรียกexit
) การดำเนินการจะดำเนินการกับคำสั่งหลังจากที่ถูกขัดจังหวะโดยสัญญาณ ที่นี่หลังจากfind
คำสั่งมาถึงจุดสิ้นสุดของสคริปต์ดังนั้นสคริปต์จะออกทันที แต่คุณสามารถเห็นความแตกต่างระหว่างการป้อน 0 และ 1 โดยการเพิ่มคำสั่งอื่น:
find /
echo "find returned $?"
วิธีทำสิ่งที่คุณต้องการ (แต่อาจไม่ควรทำ)
คุณสามารถทำสิ่งที่คุณต้องการ; แต่คำตอบของฉันส่วนนี้เกี่ยวกับการค้นพบการเขียนโปรแกรมเชลล์มากกว่าการแก้ปัญหาจริง
- ในเรื่องของการออกแบบสัญญาณที่สามารถรีสตาร์ทได้นั้นไม่ใช่สิ่งที่คุณคาดหวังในรูปแบบของโปรแกรมที่ค่อนข้างง่ายที่เชลล์สคริปต์ปกติ ความคาดหวังคือCtrl+ Cจะฆ่าสคริปต์
- ดังที่คุณเห็นด้านล่างมันยืดขีดความสามารถของเปลือกออกไปเล็กน้อย
หากคุณต้องการที่จะหลีกเลี่ยงการฆ่าfind
คุณจะต้องเริ่มต้นในพื้นหลังfind / &
: จากนั้นใช้wait
builtinเพื่อรอให้มันออกตามปกติ สัญญาณจะขัดจังหวะการwait
ติดตั้งในตัวซึ่งคุณสามารถทำงานเป็นแบบวนซ้ำจนกว่าคุณจะได้รับสัญญาณที่คุณต้องการเผยแพร่ จากนั้นใช้kill
เพื่อฆ่างาน
hell () {
echo "Do you want to quit? Press 1 for yes and 0 for no"
read n
if [ "$n" = 1 ]; then
# Kill the job if it's running, then exit
if [ -n "$job_pid" ]; then kill $job_pid; fi
exit 1
fi
}
job_pid=
trap "hell" SIGINT
# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
echo "resuming wait"
done
job_pid=
echo last exit code: $?
มีข้อ จำกัด สำหรับวิธีการนี้ในเชลล์:
- มีสภาพการแข่งขัน: ถ้าคุณกดCtrl+ Cหลังจากงานเสร็จสิ้น แต่ก่อนถึง
job_pid=
บรรทัดผู้จัดการสัญญาณจะพยายามฆ่า$jobpid
แต่กระบวนการไม่มีอยู่อีกต่อไป (แม้จะเป็นซอมบี้เพราะwait
ได้ทำการเก็บเกี่ยวแล้ว) และกระบวนการ ID อาจถูกนำมาใช้ซ้ำโดยกระบวนการอื่น สิ่งนี้ไม่สามารถแก้ไขได้อย่างง่ายดายในเชลล์ (อาจโดยการตั้งค่าตัวจัดการSIGCHLD
ใช่ไหม)
- หากคุณต้องการสถานะการส่งคืนจากงานคุณต้องใช้
wait $job_pid
แบบฟอร์ม แต่คุณไม่สามารถแยกความแตกต่าง“ wait
ถูกขัดจังหวะด้วยสัญญาณ” จาก“ งานถูกฆ่าโดยสัญญาณ” (หรือจาก“ งานถูกยกเลิกด้วยความสอดคล้องกับสถานะการส่งคืน≥128” แต่นั่นเป็นข้อเท็จจริงทั่วไปในเชลล์ การเขียนโปรแกรม)
- สิ่งนี้จะไม่ขยายออกไปได้อย่างง่ายดายหากเลยถึงหลาย ๆ subjobs โปรดทราบว่าพฤติกรรมของกับดักและสัญญาณมักจะน่าแปลกใจเมื่อคุณก้าวไปไกลกว่าพื้นฐานในการใช้งานเชลล์ส่วนใหญ่ (เฉพาะ ksh เท่านั้นที่ทำได้ดี)
หากต้องการเอาชนะข้อ จำกัด เหล่านี้ให้ใช้ภาษาที่ชอบมากกว่าเช่น Perl หรือ Python