เรียกใช้คำสั่งหลังจากผ่านไประยะเวลาหนึ่งหรือไม่


24

หากฉันกำลังดำเนินการกระบวนการที่ยาวนานจะมีวิธีใดบ้างที่ฉันสามารถเรียกใช้คำสั่งตามเวลาได้?

ตัวอย่างเช่นฉันใช้กระบวนการที่ยาวมาก ๆ ซึ่งใช้เวลาประมาณ 10 นาที

หลังจาก 5 นาทีฉันต้องการเรียกใช้คำสั่งแยกต่างหาก สำหรับภาพประกอบคำสั่งแยกอาจเป็น:echo 5 minutes complete

(หมายเหตุ: ฉันไม่ต้องการความคืบหน้าไปสู่ความสมบูรณ์ของคำสั่ง แต่เพียงคำสั่งดำเนินการหลังจากช่วงเวลาที่ระบุ)

มันเป็นไปได้?


1
ส่วนใหญ่คุณไม่ทราบล่วงหน้าว่ากระบวนการจะใช้เวลานานเท่าใด
choroba

คุณหมายถึงอะไร "คำสั่งตามเวลา"? คุณต้องการสร้างแถบความคืบหน้าหรือไม่? จากการใช้ถ้อยคำปัจจุบันของคำถามของคุณคุณสามารถใส่คำสั่งที่รันเป็นเวลานานในพื้นหลังแล้วแสดงนาฬิกาของระบบ กรุณาชี้แจง
Wildcard

@ Wildcard ฉันได้ชี้แจงในคำถาม ไม่ใช่แถบความคืบหน้า มันจะดำเนินการคำสั่งหลังจากช่วงเวลาบางอย่าง
Aniket Bhattacharyea

1
"5 นาทีเสร็จสมบูรณ์" เป็นสิ่งที่แปลกที่จะสะท้อน ไม่ใช่ "ผ่านไป 5 นาที" หรือไม่ ไม่ใช่ "เวลา _____" ใช่หรือไม่ คุณเพียงแค่ต้องการให้แน่ใจว่าช่วงเวลาที่ระบุบางส่วนผ่านไปตั้งแต่เวลาที่คำสั่งที่รันเป็นเวลานานของคุณเริ่มต้นแล้ว ถ้าเป็นเช่นนั้นทำไมไม่ทำงานเพียงlongcommand & sleep 300 && command-to-do-after-five-minutes? (ที่จริงแล้วอาจเป็นสิ่งที่คุณกำลังมองหา) โปรดทราบว่าการชี้แจงของคุณไม่เพียงพอเนื่องจากคุณมีการใช้งานแถบความคืบหน้าของนาฬิกาสองรายการทันทีที่ออกจากค้างคาว
สัญลักษณ์แทน

คำตอบ:


29

เพิ่งรัน:

long-command & sleep 300; do-this-after-five-minutes

do-this-after-five-minutesจะได้รับการทำงานหลังจากห้านาที long-commandจะทำงานในพื้นหลัง


10
ฉันมักจะใช้sleep 5m && foobarดังนั้นถ้าฉันเปลี่ยนใจและ ^ C the sleepคำสั่งถัดไปจะไม่ทำงาน
Peter Cordes

@PeterCordes เมื่อฉันทดสอบด้วยเช่นsleep 3; lsและ^Cคำสั่งที่สองไม่ทำงาน ไม่แน่ใจจริงๆว่าทำไมและบางทีมันทำงานแตกต่างกันในเปลือกแบบไม่โต้ตอบ?
Wildcard

1
@PeterCordes ไม่มาก - ยกเว้นว่ามีความแตกต่างกันในแต่ละเชลล์ เมื่อคุณsleep 5m && echoกำลังหลับเมื่อคุณหยุดชั่วคราวsleepคำสั่งเท่านั้นที่ถูกระงับ ส่วนที่เหลือของบรรทัดคำสั่งจะทำงาน แต่เนื่องจากsleepถูกระงับจึงไม่สามารถออกได้สำเร็จและส่วนหลัง&&จะถูกข้ามไป ลองระงับsleep 5 || echo helloและกดแสดงขึ้นโดยตรงหลังจากhello ^Z
hvd

1
@hvd: ใช่คุณพูดถูกและฉันผิดอีกครั้ง>. <โดยใช้ bash4 เห็นได้ชัดว่ามันนานมากแล้วนะตั้งแต่ฉันตัดสินใจว่า && เป็นวิธีที่จะไปเป็นสลัมat(1)สำหรับสิ่งที่ต้องการsleep 30m && mplayer something.mp3แจ้งเตือนปลุกหรือsleep 90m && fgเพื่อดำเนินการต่อคำสั่งดิสก์มากในภายหลัง ดังนั้นที่จริงแล้วsleep 5m && echo helloก็ดีเพราะ^Zหยุดชั่วคราวsleepโดยไม่ต้องเรียกใช้คำสั่งต่อไปเลย หากคุณต้องการที่จะสามารถที่จะระงับการ / ( sleep 2 && echo hello )ประวัติคำสั่งสารประกอบทั้งก่อนออกจากการนอนหลับการใช้งาน
Peter Cordes

@hvd: &&สำนวนช่วยให้คุณมั่นใจได้อย่างแน่นอนว่าคุณไม่ได้ฆ่ากระบวนการทันทีหลังจากการทำงานของโหมดสลีป (เพราะคุณ^Zไม่สามารถเรียกใช้คำสั่งแทนที่จะเสี่ยง a ^C) สิ่งนี้มีประโยชน์ในกรณีที่ใช้sleep && fgหรือsleep && bgเมื่อคำสั่งจะกลับมาเป็นส่วนหนึ่งผ่านสิ่งที่ช้า
Peter Cordes

5

คุณสามารถใช้สคริปต์นี้:

#!/bin/bash

TEMPFILE="$(mktemp)"
STARTTIME="$(date +%s)"
(./longprocess; rm -f "$TEMPFILE") &
while [ -f "$TEMPFILE" ]; do
    sleep 1s
    NOW="$(date +%s)"
    if (( (NOW-STARTTIME) % 300 == 0 )); then
        echo "$(( (NOW-STARTTIME)/60 )) minute(s) elapsed"
    fi
done
echo "Done!!!"

มันทำงานของคุณlongprocessในsub-shellและจากนั้นตรวจสอบไฟล์ 'ล็อค' สร้างขึ้นก่อนหน้านี้สำหรับการดำรงอยู่


2
ตรวจสอบสำหรับman bash SECONDSคุณสามารถตั้งค่าSECONDS=0เมื่อเริ่มต้นสคริปต์และตรวจสอบมากกว่าหรือเท่ากับ 300 หรือตั้งค่าSECONDS=$((date +%s))และลืมใช้dateอีกครั้งในสคริปต์ของคุณ ...

@ yeti ขอบคุณสำหรับคำใบ้ฉันไม่ทราบว่า
Serge

@yeti ถ้าคุณต้องการที่จะพึ่งพาเวลาหลังจากsleep 1sเสมอว่าคนที่สองภายหลังกว่า แต่ก่อนsleep 1s... แล้วคุณได้ตกเป็นเหยื่อเท็จว่าโปรแกรมเมอร์เชื่อเกี่ยวกับเวลา (แม้ว่าในกรณีนี้คุณอาจแสดงแถบความคืบหน้าของเครื่องหมายแฮชหรืออะไรก็ได้)
Wildcard

@ Wildcard ... ฉันไม่ได้เอ่ยถึงsleepเลย!

@ yeti ใช่มั้ย ขอบคุณสำหรับเคล็ดลับเกี่ยวกับSECONDS! :)
สัญลักษณ์แทน

4

มีหนึ่งซับสำหรับสิ่งนี้:

( ( sleep $TIMEOUT ; echo "5 minutes complete") & $COMMAND )

ในกรณีของคุณ TIMEOUT = 5m และคำสั่งคือคำสั่งแบบยาว

ดูคำตอบของฉันที่โพสต์นี้ด้วยการหมดเวลาด้วย 'บริการเครือข่ายเริ่มต้นใหม่'


การเรียกใช้ subshell ในเบื้องหน้าจากนั้นเรียกใช้งานคำสั่งนั้นดูซับซ้อนโดยไม่จำเป็น ฉันจะลบวงเล็บด้านนอกและ exec
เกล็นแจ็

1
@glennjackman วิธีนี้สามารถฆ่าโพรซีเดอร์ทั้งหมดที่ส่ง CTRL + C (ตัวอย่าง) ไปยัง sub-shell หลัก (นอกสุด)
coffeMug

1
แต่เมื่อใช้ exec คุณจะไม่ได้ subshell อีกต่อไปคุณแค่มีคำสั่ง พาเรนต์ของคำสั่งคือเชลล์ที่รันสคริปต์เหมือนกับว่าคุณไม่ได้ใช้เชลล์ย่อยเลย
เกล็นแจ็

3
#! /bin/bash

( sleep 4 ) & # <-- The long running process.

seconds=1
while jobs %1 &>/dev/null ; do
    echo $((seconds++)) seconds complete
    sleep 1    
done
echo Done.

jobs %1 ล้มเหลวเมื่องาน% 1 หยุดทำงาน

โปรดทราบว่าเป็นเวลานานกว่า $ วินาทีอาจไม่ซิงค์กับเวลาจริง เป็นการดีกว่าที่จะเก็บเวลาเริ่มต้นและคำนวณความแตกต่างตามเวลาจริง

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