Shell: เป็นไปได้ไหมที่จะชะลอคำสั่งโดยไม่ใช้ `sleep '?


21

มีการทดแทนทางเลือกหรือเทคนิคทุบตีสำหรับการชะลอคำสั่งโดยไม่ใช้sleepหรือไม่? ตัวอย่างเช่นการแสดงคำสั่งด้านล่างโดยไม่ใช้สลีปจริง:

$ sleep 10 && echo "This is a test"

42
มีอะไรผิดปกติกับsleep?
muru

5
ไม่มีเหตุผลที่แท้จริงนอกจากความอยากรู้ ฉันคิดว่ามันน่าสนใจที่จะเรียนรู้วิธีแก้ปัญหาทางเลือก ฉันคิดว่าatอาจเป็นหนึ่ง แต่ฉันไม่พบตัวอย่างการใช้งานใด ๆ
user321697

1
@ user321697“ at” เป็นการกำหนดเวลางานเดียว พวกเขาจะถูกดำเนินการโดยบริการ atd ดังนั้นพวกเขาจะไม่หยุดสคริปต์เชลล์ของคุณชั่วคราว กรณีการใช้งานหนึ่งกรณีสำหรับ at คือให้ทำบางสิ่งตามเวลาที่กำหนด (async) และสร้างไฟล์ทำเครื่องหมายเมื่อดำเนินการเสร็จในขณะที่สคริปต์ของคุณกำลังรอให้ไฟล์นั้นปรากฏในขณะที่ลูป คุณสามารถบรรลุผลที่คล้ายกันโดยการกำหนดเวลางานเพื่อส่ง SIGCONT ของคุณให้กับสคริปต์แล้วจึงทำการตรึงสคริปต์ของคุณโดยส่ง SIGSTOP ให้ตัวเอง
Grega Bremec

1
ฉันมาที่นี่โดยหวังว่าทุกคนจะแนะนำ spinlock ฉันประหลาดใจด้วยคำตอบทั้งหมด
Daan van Hoek

3
Re: "อยากรู้อยากเห็น" - ในunix.stackexchange.com/help/dont-askโปรดทราบข้อกำหนดว่า"คุณควรถามคำถามที่ตอบได้จริงและตอบได้ตามปัญหาจริงที่คุณเผชิญ " - สิ่งนี้ได้รับอย่างดี ได้รับแม้จะมีการโต้แย้งว่าแนวทางทำให้มันเป็นข้อยกเว้นที่ค่อนข้างหายาก
Charles Duffy

คำตอบ:


17

คุณมีทางเลือกในการsleep: พวกเขาและat cronตรงกันข้ามกับsleepสิ่งเหล่านี้คุณต้องให้เวลาที่คุณต้องการให้พวกเขาทำงาน

  • ให้แน่ใจว่าบริการกำลังทำงานโดยการดำเนินการatd ตอนนี้สมมติว่าวันที่ 11:17 น. UTC ถ้าคุณจำเป็นต้องดำเนินการคำสั่งที่ 11:25 UTC ไวยากรณ์คือ: พึงระลึกไว้ว่าโดยค่าเริ่มต้นจะไม่ทำการบันทึกงานที่เสร็จสมบูรณ์ สำหรับอ้างอิงเพิ่มเติมลิงค์นี้ จะดีกว่าที่แอปพลิเคชันของคุณมีการบันทึกของตัวเองservice atd status
    echo "This is a test" | at 11:25
    atd

  • คุณสามารถกำหนดเวลางานcronเพื่ออ้างอิงเพิ่มเติม: man cronเพื่อดูตัวเลือกหรือcrontab -eเพิ่มงานใหม่ /var/log/cronสามารถตรวจสอบข้อมูลเกี่ยวกับการดำเนินการกับงานได้

FYI sleep system call ระงับการดำเนินการปัจจุบันและกำหนดเวลาให้อาร์กิวเมนต์โต้แย้งผ่านไป

แก้ไข:

ในฐานะที่เป็น @Gaius กล่าวถึงคุณยังสามารถเพิ่มเวลานาทีเพื่อatcommand.But ช่วยบอกเวลาและตอนนี้คุณวิ่งจัดตารางเวลาที่มี12:30:30 now +1 minutesแม้ว่าจะระบุเวลา 1 นาทีซึ่งแปลเป็น 60 วินาที แต่ก็atไม่ได้รอจนกว่า12:31:30จะทำงาน12:31:00จริง minutes, hours, days, or weeksเวลาที่หน่วยสามารถ สำหรับการอ้างอิงเพิ่มเติมman at

เช่น: echo "ls" | at now +1 minutes


7
สิ่งนี้ไม่เป็นความจริงคุณสามารถกำหนดเวลาที่งานเพื่อพูดได้ในขณะนี้ +1 นาทีเพื่อให้ทำงานได้ในเวลาไม่กี่นาที
Gaius

29

ด้วยbashbuiltins คุณสามารถทำได้:

coproc read -t 10 && wait "$!" || true

การนอนหลับเป็นเวลา 10 sleepวินาทีโดยไม่ต้องใช้ สิ่งที่coprocต้องทำเพื่อให้readstdin เป็นท่อที่ไม่มีอะไรจะออกมา || trueเป็นเพราะwaitสถานะทางออกของจะสะท้อนถึงการส่งมอบ SIGALRM ซึ่งจะทำให้เชลล์ออกหากerrexitตั้งค่าตัวเลือก

ในเปลือกหอยอื่น ๆ :

mkshและksh93มีsleepอยู่แล้วภายในไม่มีประโยชน์ในการใช้สิ่งอื่นที่นั่น (แม้ว่าพวกเขาทั้งสองจะรองรับread -t)

zshยังรองรับread -tแต่ยังมี wrapper builtin select()ดังนั้นคุณสามารถใช้:

zmodload zsh/zselect
zselect -t 1000 # centiseconds

หากสิ่งที่คุณต้องการคือกำหนดเวลาให้สิ่งต่าง ๆ ถูกเรียกใช้จากเซสชันเชลล์แบบโต้ตอบให้ดูzsh/schedโมดูลzshด้วย


คุณจะพิจารณาread -t 10 < /dev/zero || trueไหม
Jeff Schaller

5
@JeffSchaller ฉันจะหลีกเลี่ยงเพราะมันเป็นวงที่ไม่ว่าง
Stéphane Chazelas

@ StéphaneChazelasฉันไม่คาดหวังว่าจะเป็นวงที่ยุ่ง - ฉันคาดว่าเชลล์ใด ๆreadที่จะใช้งานโดยเลือก (2) หรือบางสิ่งที่คล้ายกัน ฉันแสดงความประหลาดใจมากกว่าที่จะแย้งคุณ แต่คุณสามารถชี้ไปที่การอภิปรายเพิ่มเติมนี้ได้หรือไม่?
นอร์แมนเกรย์

5
@NormanGray /dev/zeroเป็นไฟล์ที่มีจำนวนข้อมูลไม่สิ้นสุด (NUL ไบต์) ดังนั้นreadจะอ่านมากที่สุดเท่าที่จะทำได้ในช่วง 10 วินาทีนั้น โชคดีที่ในกรณีbashที่ไม่รองรับการจัดเก็บ NUL ไบต์ในตัวแปรซึ่งจะไม่ใช้หน่วยความจำใด ๆ แต่จะยังคงเป็นทรัพยากรของ CPU
Stéphane Chazelas

1
@NormanGray หากเรียกใช้จากเทอร์มินัล/dev/stdoutจะเป็นอุปกรณ์ tty ดังนั้นมันจะมีผลข้างเคียง (เช่นหยุดสคริปต์ถ้าทำงานในพื้นหลัง) และจะกลับมาถ้าผู้ใช้กดป้อนเช่น read -t 10 /dev/stdout | :จะทำงานบน Linux แต่บน Linux เท่านั้นในขณะที่coprocควรทำงานโดยไม่คำนึงถึงระบบปฏิบัติการ
Stéphane Chazelas

7

ความคิดอื่น ๆ

top -d10 -n2 >/dev/null

vmstat 10 2 >/dev/null

sar 10 1 >/dev/null

timeout 10s tail -f /dev/null

1
คุณ "ขโมย" ความคิดของฉันเกี่ยวกับ timelimit / timeout .... +1
Rui F Ribeiro

1
โอ้วววขอบคุณฉันอยู่ในสถานการณ์ที่ไม่ต้องนอนหลับส่วนบนนั้นน่าทึ่งมาก!
Fire-Dragon-DoL

6

เนื่องจากมีคำตอบที่แนะนำให้ใช้-t delayตัวเลือกที่ไม่ได้มาตรฐานreadนี่คือวิธีอ่านการหมดเวลาในเชลล์มาตรฐาน:

{ ss=`stty -g`; stty -icanon min 0 time 20; read foo; stty "$ss"; }

อาร์กิวเมนต์ที่stty timeอยู่ในสิบส่วนของวินาที


5

การใช้ตัวแปรในตัวของ bash $SECONDSและ busy-loop:

for((target=$((SECONDS + 10)); SECONDS < target; true)); do :; done

2
ที่จะหยุดการทำงานชั่วคราวในผลกระทบในช่วงระยะเวลาตั้งแต่ที่ไหนสักแห่งในระหว่างวันที่ 9 และ 10 วินาทีแม้ว่า (เนื่องจากข้อผิดพลาดในbash ; zshและmkshมีปัญหาที่คล้ายกัน แต่ได้รับการแก้ไขตั้งแต่)
Stéphane Chazelas

7
วิธีที่ดีในการสร้างความร้อน
ctrl-alt-delor

6
จะไม่เป็นครั้งแรกที่ฉันถูกกล่าวหาว่าเต็มไปด้วยอากาศร้อน! :)
Jeff Schaller

4

เคล็ดลับที่เก่าแก่ที่สุดในหนังสือ:

read && echo "This is a test"

เพียงแค่กดEnterและมันจะดำเนินต่อไป!


สิ่งนี้จะไม่เกิดขึ้นหากกระบวนการจำเป็นต้องเรียกใช้การโต้ตอบฟรีหรือในพื้นหลังใช่ไหม
ss_iwe

ถูกต้อง: แต่นั่นไม่ใช่ข้อกำหนดของ OP ตามคำถามเดิมดังนั้นยังคงเป็นคำตอบที่ถูกต้อง ...
;

1
OP แสดงตัวอย่าง (พร้อมsleep) และขอทางเลือกอื่นที่เทียบเท่าโดยไม่ต้อง ดังนั้นreadอย่าแยกวิเคราะห์ขอโทษ ;)
AnoE

@AnoE Stéphaneเป็นคำตอบที่ดีที่สุดแน่นอนที่สุดเหมืองเป็นเพียง--- press «enter» to continue --- ;-) ที่ดีที่สุด
Fabby

4

ย้อนกลับไปในสมัยของไมโครคอมพิวเตอร์ที่ใช้งาน BASIC ความล่าช้ามักเกิดขึ้นได้ด้วยการวนซ้ำที่ว่างเปล่า:

FOR I = 1 TO 10000:NEXT

หลักการเดียวกันนี้สามารถใช้เพื่อแทรกการหน่วงเวลาในเชลล์สคริปต์:

COUNTER=0; while [ $COUNTER -lt 10000 ]; do :; let COUNTER=COUNTER+1; done

แน่นอนปัญหาด้วยวิธีนี้คือความยาวของการหน่วงเวลาจะแตกต่างกันไปตามเครื่องกับเครื่องตามความเร็วโปรเซสเซอร์ (หรือแม้กระทั่งในเครื่องเดียวกันภายใต้การโหลดที่แตกต่างกัน) ซึ่งแตกต่างจากsleepมันอาจจะสูงสุด CPU ของคุณ (หรือหนึ่งในแกนของมัน)


2
วิธีที่ดีในการสร้างความร้อน
ctrl-alt-delor

2
Delay-loops เป็นความคิดที่เลวร้ายสำหรับทุกสิ่งยกเว้นสลีปที่สั้นที่สุด (ไม่กี่นาโนวินาทีหรือวงจรนาฬิกาในไดรเวอร์อุปกรณ์) บนซีพียูสมัยใหม่ที่สามารถใช้ระบบปฏิบัติการ Unix ได้ นั่นคือการสลีปสั้นมากคุณไม่สามารถให้ CPU ทำอะไรอย่างอื่นได้ในขณะที่รอเช่นกำหนดเวลากระบวนการอื่นหรือเข้าสู่โหมดสลีปที่ใช้พลังงานต่ำ Dynamic CPU-frequency ทำให้ไม่สามารถทำการปรับลูปการหน่วงเวลาสำหรับนับต่อวินาทียกเว้นการหน่วงเวลาต่ำสุดอาจทำให้หลับนานขึ้นมากที่ความเร็วสัญญาณนาฬิกาต่ำก่อนที่จะกระโจนขึ้น
Peter Cordes

คอมพิวเตอร์โบราณมีการใช้พลังงานที่น้อยมากขึ้นอยู่กับภาระงาน ซีพียูสมัยใหม่จำเป็นต้องปิดส่วนต่าง ๆ ของชิปแบบไดนามิกให้มากที่สุดเท่าที่จะทำได้เพื่อไม่ให้ละลาย (เช่นปิดส่วนต่าง ๆ ของหน่วยดำเนินการ FPU หรือ SIMD ในขณะที่ใช้รหัสเลขจำนวนเต็มเท่านั้นหรืออย่างน้อยประตูสัญญาณนาฬิกาไปยังส่วนต่างๆของชิป ที่ไม่จำเป็นต้องสลับ) และการเข้าสู่โหมดสลีปพลังงานต่ำเมื่อไม่ได้ใช้งาน (แทนที่จะหมุนวนเป็นวงวนไม่สิ้นสุดที่รอการขัดจังหวะตัวจับเวลา) ก็ยังใหม่กว่าคอมพิวเตอร์โบราณที่คุณพูดถึง
Peter Cordes

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับประวัติของ CPU ดูที่ไมโครโปรเซสเซอร์สมัยใหม่คำแนะนำ 90 นาที! - lighterra.com/papers/modernmicroprocessors
Peter Cordes

3

ไม่มีในตัวที่ทำเช่นเดียวกับsleep(เว้นแต่sleepจะมีในตัว) อย่างไรก็ตามมีคำสั่งอื่น ๆ ที่จะรอ

รวมถึงไม่กี่

  • atและcron: ใช้เพื่อกำหนดเวลางานในเวลาที่กำหนด

  • inotifywait: ใช้เพื่อรอไฟล์หรือไฟล์ที่จะแก้ไข / ลบ / เพิ่ม / ฯลฯ


ขอบคุณสำหรับสิ่งนี้. คุณสามารถยกตัวอย่างสำหรับการทำงานตามกำหนดเวลา (10 วินาทีต่อจากนี้) ด้วยat?
user321697

1
แก้ไขและ upvote! ;-)
Fabby

cronจัดเก็บงานในcrontabใช่มั้ย สถานที่ที่ไม่atจัดเก็บข้อมูลที่กำหนดไว้หรือไม่
user321697

@ user321697 ตอบแล้วที่นี่
Fabby

ขออภัยสำหรับการคืนค่าการแก้ไขของคุณกลับเป็น Q: คุณเปลี่ยนวัตถุประสงค์หลักของคำถาม OPs ซึ่งจะทำให้คำตอบที่ง่ายที่สุดของทั้งหมด ... ¯ \ _ (ツ) _ / ¯
Fabby

3

คลาสสิกจากดินแดนแห่ง Windows และรุ่นที่:

ping -c 11 localhost >/dev/null && echo "This is a test"

การตั้งค่าผิดพลาดของไฟร์วอลล์หรือระบบชื่ออาจทำให้การหน่วงเวลาล่าช้าเพิ่มขึ้นอย่างเห็นได้ชัด
สเปกตรัม

1
127.0.0.1 ... @spectras
AnoE

1
โชคไม่ดีที่ไม่ต้องการอีกต่อไปเนื่องจาก Windows รองรับการสลีป
Baldrickk

1
@AnoE> แก้ไขส่วนของระบบชื่อไม่ใช่ส่วนของไฟร์วอลล์ แม้ว่าจะไม่ใช่เรื่องธรรมดา แต่ก็สามารถกำหนดค่าให้ส่ง Ping แบบไม่มีการโต้ตอบบนโลคัลอินเตอร์เฟส นั่นจะทำให้ปิงต้องรอนานกว่านี้
สเปกตรัม

+1 สำหรับความทรงจำที่ "ชอบ"
AC

0

หากคุณต้องการรอการโต้ตอบบรรทัดใหม่ในไฟล์แล้ว

tail -f
.

กำลังรอการเปลี่ยนแปลงในระบบไฟล์หรือไม่? จากนั้นใช้เช่น

inotify / inoticoming
.

และมีตัวเลือกอื่น ๆ ขึ้นอยู่กับสิ่งที่คุณหมายถึงด้วย "รอ"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.