POSIX เทียบเท่ากับการหมดเวลาของ GNU หรือไม่


14

timeoutคำสั่งGNU coreutils มีประโยชน์อย่างยิ่งสำหรับสถานการณ์การเขียนสคริปต์บางอย่างซึ่งอนุญาตให้ใช้เอาต์พุตของคำสั่งหากมันรวดเร็วในการเรียกใช้และข้ามมันหากมันใช้เวลานานเกินไป

ฉันจะประมาณพฤติกรรมพื้นฐานของการtimeoutใช้ยูทิลิตี้ที่ระบุเฉพาะ POSIX ได้อย่างไร


(ฉันคิดว่ามันอาจจะเกี่ยวข้องกับการรวมกันของwait, sleep, killและผู้ที่รู้สิ่งอื่น แต่บางทีฉันหายไปวิธีการที่ง่ายขึ้น.)


3
ดูที่Timing out ในเชลล์สคริปต์แต่ฉันไม่พิจารณาสิ่งนี้ซ้ำเพราะฉันขอความสะดวกในการพกพาไปยังระบบ POSIX ล่วงหน้าและฉันมีความต้องการในการรักษา stdin และ stdout ซึ่งโซลูชันบางอย่างที่เกี่ยวข้องกับกระบวนการพื้นหลังออกกฎ
Gilles 'SO- หยุดความชั่วร้าย'

command & pid=$! ; sleep 5 && kill $pid
Pandya

1
@Pandya ไม่ได้แนะนำสภาพการแข่งขันเล็กน้อยซึ่งหากทำcommandเสร็จอย่างรวดเร็วมีโอกาสน้อยที่จะpidถูกนำกลับมาใช้โดยกระบวนการอื่นที่เริ่มต้นขึ้นก่อนที่killคำสั่งจะทำงานหรือไม่ ฉันไม่ต้องการรหัสนั้นในการผลิต ....
ไวด์การ์ด

คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับปัญหาพื้นฐานที่คุณพยายามแก้ไขได้ไหม? ทำไมไม่รวบรวมtimeoutโปรแกรมและใช้มัน?
James Youngman

2
@JamesYoungman ผมคาดเดาคุณไม่คุ้นเคยกับการเขียนสคริปต์สำหรับการพกพา การขอวิธีที่สอดคล้องกับ POSIX (หรือ POSIX ที่ระบุ) ในการทำบางสิ่งบ่งบอกว่ามันตั้งใจจะพกพา การคอมไพล์ซอร์สโค้ดลงในไบนารีนั้นไม่สามารถพกพาได้อย่างชัดเจนและขึ้นอยู่กับนโยบายความปลอดภัยของ บริษัท คุณอาจไม่มีคอมไพเลอร์ติดตั้งเลยบนเซิร์ฟเวอร์ที่ใช้งานจริง
Wildcard

คำตอบ:


2

แนวทางของฉันจะเป็นอย่างนี้:

  • ดำเนินการคำสั่งเป็นกระบวนการพื้นหลัง 1

  • ดำเนินการ "ตัวจับเวลาจ้องจับผิด" เป็นกระบวนการพื้นหลัง 2

  • ตั้งค่าตัวจัดการเพื่อดักจับสัญญาณการเลิกจ้างในเชลล์พาเรนต์

  • รอให้กระบวนการทั้งสองเสร็จสมบูรณ์ กระบวนการที่ยุติก่อนส่งสัญญาณการเลิกจ้างไปยังผู้ปกครอง

  • ตัวจัดการแทร็บของพาเรนต์ฆ่ากระบวนการพื้นหลังทั้งสองผ่านการควบคุมงาน (หนึ่งในนั้นได้ยกเลิกไปแล้วตามคำจำกัดความ แต่การฆ่านั้นจะไม่เป็นอันตรายโดยไม่มี op เนื่องจากเราไม่ได้ใช้ PID ดูด้านล่าง)

ฉันพยายามหลีกเลี่ยงสภาพการแข่งขันที่เป็นไปได้ที่ระบุไว้ในความคิดเห็นโดยใช้ ID การควบคุมงานของเชลล์ (ซึ่งจะไม่ชัดเจนในอินสแตนซ์เชลล์นี้) เพื่อระบุกระบวนการพื้นหลังที่จะฆ่าแทนที่จะเป็นระบบ PID

#!/bin/sh

TIMEOUT=$1
COMMAND='sleep 5'

function cleanup {
    echo "SIGTERM trap"
    kill %1 %2
}

trap cleanup SIGTERM

($COMMAND; echo "Command completed"; kill $$) &
(sleep $TIMEOUT; echo "Timeout expired"; kill $$) &

wait
echo "End of execution"

ผลลัพธ์สำหรับTIMEOUT=10(คำสั่งสิ้นสุดก่อนที่สุนัขเฝ้าบ้าน):

$ ./timeout.sh 10
Command completed
SIGTERM trap
End of execution

ผลลัพธ์สำหรับTIMEOUT=1(watchdog ยุติก่อนคำสั่ง):

$ ./timeout.sh 1
Timeout expired
SIGTERM trap
End of execution

ผลลัพธ์สำหรับTIMEOUT=5(watchdog และคำสั่งยุติ "เกือบ" พร้อมกัน):

./tst.sh 5
Timeout expired
Command completed
SIGTERM trap
End of execution

สิ่งนี้ไม่เป็นไปตาม POSIX เนื่องจาก (a) นิยามฟังก์ชันควรเป็นcleanup() { ...; }และ (b) การควบคุมงานเป็นคุณสมบัติทุบตีที่ POSIX ไม่ได้ระบุไว้ (แม้ว่า ksh และอื่น ๆ จะมี) สคริปต์ที่ดี แต่!
Wildcard

คุณสามารถทำได้ดีกว่าด้วยtimeout="$1"; shiftและ(exec "$@"; echo "Command completed"; kill $$)แทนที่จะใส่คำซ้ำอีกครั้งในรายการอาร์กิวเมนต์
Wildcard
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.