Jalankan perintah setelah jangka waktu tertentu telah berlalu?

24

Jika saya menjalankan proses yang panjang, apakah ada cara saya dapat menjalankan beberapa perintah berbasis waktu?

Sebagai contoh, saya menjalankan proses yang sangat panjang yang berjalan sekitar 10 menit.

Setelah 5 menit, saya ingin menjalankan perintah terpisah. Sebagai ilustrasi, perintah terpisah dapat berupa:echo 5 minutes complete

(Catatan: Saya tidak ingin kemajuan menuju penyelesaian perintah, tetapi hanya perintah yang dieksekusi setelah interval yang ditentukan.)

Apa itu mungkin?

Aniket Bhattacharyea
sumber
1
Seringkali, Anda tidak tahu sebelumnya berapa lama prosesnya.
choroba
Apa maksudmu "perintah berbasis waktu"? Apakah Anda ingin membuat bilah kemajuan? Berdasarkan ungkapan saat ini dari pertanyaan Anda, Anda bisa meletakkan perintah lama berjalan di latar belakang dan kemudian menampilkan jam sistem. Mohon klarifikasi.
Wildcard
@ Kartu Memori saya mengklarifikasi dalam pertanyaan. Bukan bilah kemajuan. Ini akan menjalankan perintah setelah beberapa interval
Aniket Bhattacharyea
1
"5 menit selesai" adalah hal yang aneh untuk digaungkan. Tidak "5 menit berlalu"? Bukan "Waktunya adalah _____"? Apakah Anda hanya ingin memastikan bahwa beberapa interval waktu tertentu telah berlalu sejak saat perintah lama Anda dimulai, sebelum perintah lain dijalankan? Jika demikian, mengapa tidak lari saja longcommand & sleep 300 && command-to-do-after-five-minutes? (Sebenarnya itu mungkin yang Anda cari.) Perhatikan bahwa klarifikasi Anda tidak cukup, karena Anda mendapatkan dua implementasi clock-progress-bar langsung dari awal.
Wildcard

Jawaban:

29

Lari saja:

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

The do-this-after-five-minutesakan terlindas setelah lima menit. Ini long-commandakan berjalan di latar belakang.

Wildcard
sumber
10
Saya biasanya menggunakan sleep 5m && foobar, jadi jika saya berubah pikiran dan ^ C sleep, perintah berikutnya tidak berjalan.
Peter Cordes
@PeterCordes, ketika saya mengujinya dengan eg sleep 3; lsdan ^C, perintah kedua tidak berjalan. Tidak begitu yakin mengapa dan mungkin ini bekerja secara berbeda dalam cangkang non-interaktif?
Wildcard
1
@PeterCordes Tidak cukup - kecuali berbeda per shell. Saat sleep 5m && echotidur, saat Anda menangguhkan, hanya sleepperintah yang ditangguhkan. Sisa dari baris perintah berjalan, tetapi karena sleepditangguhkan, itu tidak berhasil keluar, dan bagian setelah &&dilewati. Coba tunda sleep 5 || echo hello, dan hellomuncul langsung setelah menekan ^Z.
hvd
1
@ DVD: Ya, Anda benar, dan saya salah lagi>. <, menggunakan bash4. Tampaknya sudah terlalu lama sejak saya memutuskan bahwa && adalah cara untuk pergi sebagai ghetto at(1), untuk hal-hal seperti sleep 30m && mplayer something.mp3pengingat alarm, atau untuk sleep 90m && fgmelanjutkan perintah intensif disk nanti. Jadi sebenarnya, sleep 5m && echo helloitu bagus karena ^Zditangguhkan sleeptanpa menjalankan perintah berikut sama sekali. Jika Anda ingin dapat menunda / melanjutkan seluruh perintah majemuk, bahkan sebelum tidur keluar, gunakan ( sleep 2 && echo hello ).
Peter Cordes
@ Hvd: &&Ungkapannya membuat Anda benar-benar yakin Anda tidak membunuh proses segera setelah tidur berjalan (karena Anda bisa ^Zuntuk tidak menjalankan perintah, alih-alih mengambil risiko a ^C). Ini berguna dalam sleep && fgatau sleep && bguse-case, ketika perintah yang dilanjutkan adalah bagian dari sesuatu yang lambat.
Peter Cordes
5

Anda dapat menggunakan skrip ini:

#!/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!!!"

Itu mengeksekusi Anda longprocessdalam sub-shelldan kemudian memantau file 'kunci' yang dibuat sebelumnya untuk keberadaan.

Serge
sumber
2
Periksa man bashuntuk SECONDS. Anda dapat mengatur SECONDS=0di awal skrip dan hanya memeriksa lebih besar atau sama dengan 300 atau mengatur SECONDS=$((date +%s))dan lupa menggunakan datelagi di skrip Anda ...
@yeti, terima kasih atas petunjuknya, saya tidak tahu itu.
Serge
@yeti, jika Anda ingin mengandalkan waktu setelah sleep 1sselalu tepat satu detik lebih lambat daripada sebelumnya sleep 1s... maka Anda telah menjadi korban Kepalsuan yang diprogram oleh programmer tentang waktu . (Meskipun dalam hal ini, Anda mungkin juga hanya menunjukkan tanda kemajuan tanda pagar atau sesuatu.)
Wildcard
@ Kartu Memori ... Saya tidak menyebutkan sleepsama sekali!
@yeti, benar kamu. Terima kasih atas tipnya SECONDS! :)
Wildcard
4

Ada satu liner untuk ini:

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

Dalam kasus Anda TIMEOUT = 5m dan PERINTAH adalah perintah panjang.

Lihat jawaban saya untuk posting ini Timeout dengan 'service network restart'

coffeMug
sumber
Meluncurkan subkulit di latar depan dan kemudian menjalankan perintah tampaknya tidak perlu rumit. Saya akan menghapus kurung luar dan eksekutif.
glenn jackman
1
@glennjackman Dengan cara ini seseorang dapat membunuh seluruh prosedur pengiriman CTRL + C (misalnya) ke sub-shell utama (terluar).
coffeMug
1
Tetapi menggunakan exec, Anda tidak memiliki subkulit lagi, Anda hanya memiliki perintah. Perintah induk adalah shell yang menjalankan skrip sama seperti jika Anda belum menggunakan subshell sama sekali.
glenn jackman
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 gagal setelah pekerjaan% 1 berhenti.

Perhatikan bahwa untuk waktu yang lebih lama, $ detik mungkin tidak sinkron dengan waktu nyata. Lebih baik menyimpan waktu mulai dan menghitung perbedaannya dengan waktu aktual.

choroba
sumber