Karena pertanyaan ini diajukan 4 tahun yang lalu, bagian pertama ini menyangkut versi bash lama :
Edit terakhir: Rabu, 22 Apr 2020, antara pukul 10.30 dan 10.00: 55 (Penting untuk membaca sampel)
Metode umum (Hindari garpu yang tidak berguna!)
(Catatan: metode ini menggunakan date -f
yang bukan POSIX dan tidak berfungsi di MacOS! Jika di bawah Mac, goto my purepestafungsi )
Untuk mengurangi forks
, daripada menjalankan date
dua kali, saya lebih suka menggunakan ini:
Sampel awal yang sederhana
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
di mana tomorrow 21:30
dapat diganti dengan segala jenis tanggal dan format yang dikenali date
, di masa mendatang.
Dengan presisi tinggi (nanosec)
Hampir sama:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Mencapai lain kali
Untuk mencapai makna selanjutnyaHH:MM
hari ini jika memungkinkan, besok jika terlambat:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Ini bekerja di bawah pesta, ksh dan cangkang modern lainnya, tetapi Anda harus menggunakan:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
di bawah cangkang yang lebih ringan sepertiAbu atau berlari.
Murni pesta jalan, tidak ada garpu !!
Diuji di bawah MacOS!
Saya menulis satu dua fungsi kecil: sleepUntil
dansleepUntilHires
Syntax:
sleepUntil [-q] <HH[:MM[:SS]]> [more days]
-q Quiet: don't print sleep computed argument
HH Hours (minimal required argument)
MM Minutes (00 if not set)
SS Seconds (00 if not set)
more days multiplied by 86400 (0 by default)
Karena versi baru bash menawarkan printf
opsi untuk mengambil tanggal, untuk cara baru tidur ini hingga HH: MM tanpa menggunakan date
atau garpu lain, saya telah membangun sedikitpestafungsi. Ini dia:
sleepUntil() {
local slp tzoff now quiet=false
[ "$1" = "-q" ] && shift && quiet=true
local -a hms=(${1//:/ })
printf -v now '%(%s)T' -1
printf -v tzoff '%(%z)T\n' $now
tzoff=$((0${tzoff:0:1}(3600*${tzoff:1:2}+60*${tzoff:3:2})))
slp=$((
( 86400+(now-now%86400) + 10#$hms*3600 + 10#${hms[1]}*60 +
${hms[2]}-tzoff-now ) %86400 + ${2:-0}*86400
))
$quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+slp))
sleep $slp
}
Kemudian:
sleepUntil 10:37 ; date +"Now, it is: %T"
sleep 49s, -> Wed Apr 22 10:37:00 2020
Now, it is: 10:37:00
sleepUntil -q 10:37:44 ; date +"Now, it is: %T"
Now, it is: 10:37:44
sleepUntil 10:50 1 ; date +"Now, it is: %T"
sleep 86675s, -> Thu Apr 23 10:50:00 2020
^C
Jika target sebelum ini akan tidur sampai besok:
sleepUntil 10:30 ; date +"Now, it is: %T"
sleep 85417s, -> Thu Apr 23 10:30:00 2020
^C
sleepUntil 10:30 1 ; date +"Now, it is: %T"
sleep 171825s, -> Fri Apr 24 10:30:00 2020
^C
Waktu HiRes dengan pesta di bawah GNU / Linux
Baru pesta, dari versi 5.0 tambahkan $EPOCHREALTIME
variabel baru dengan mikrodetik. Dari sini ada sleepUntilHires
fungsi.
sleepUntilHires () {
local slp tzoff now quiet=false musec musleep;
[ "$1" = "-q" ] && shift && quiet=true;
local -a hms=(${1//:/ });
printf -v now '%(%s)T' -1;
IFS=. read now musec <<< $EPOCHREALTIME;
musleep=$[2000000-10
printf -v tzoff '%(%z)T\n' $now;
tzoff=$((0${tzoff:0:1}(3600*${tzoff:1:2}+60*${tzoff:3:2})));
slp=$(((( 86400 + ( now - now%86400 ) +
10#$hms*3600+10#${hms[1]}*60+10#${hms[2]} -
tzoff - now - 1
) % 86400 ) + ${2:-0} * 86400
)).${musleep:1};
$quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+${slp%.*}+1));
read -t $slp foo
}
Harap dicatat: penggunaan ini read -t
yang sudah built-in, bukan sleep
. Sayangnya, ini tidak akan berfungsi saat berjalan di latar belakang, tanpa TTY asli. Jangan ragu untuk mengganti read -t
dengan sleep
jika Anda berencana untuk menjalankan ini di skrip latar belakang ... (Tetapi untuk proses latar belakang, pertimbangkan untuk menggunakan cron
dan / atau at
alih-alih semua ini)
Lewati paragraf berikutnya untuk tes dan peringatan tentang $ËPOCHSECONDS
!
Kernel terbaru menghindari penggunaan /proc/timer_list
oleh pengguna !!
Di bawah kernel Linux terbaru, Anda akan menemukan file variabel bernama `/ proc / timer_list` di mana Anda dapat membaca variabel` offset` dan `now`, dalam ** nanodetik **. Jadi, kami dapat menghitung waktu tidur untuk mencapai waktu * paling atas * yang diinginkan.
(Saya menulis ini untuk menghasilkan dan melacak peristiwa tertentu pada file log yang sangat besar, berisi ribuan baris untuk satu detik).
mapfile </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
[[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_SKIP=$_i
[[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
break
done
unset _i _timer_list
readonly TIMER_LIST_OFFSET TIMER_LIST_SKIP
sleepUntilHires() {
local slp tzoff now quiet=false nsnow nsslp
[ "$1" = "-q" ] && shift && quiet=true
local hms=(${1//:/ })
mapfile -n 1 -s $TIMER_LIST_SKIP nsnow </proc/timer_list
printf -v now '%(%s)T' -1
printf -v tzoff '%(%z)T\n' $now
nsnow=$((${nsnow//[a-z ]}+TIMER_LIST_OFFSET))
nsslp=$((2000000000-10#${nsnow:${#nsnow}-9}))
tzoff=$((0${tzoff:0:1}(3600*${tzoff:1:2}+60*${tzoff:3:2})))
slp=$(( ( 86400 + ( now - now%86400 ) +
10#$hms*3600+10#${hms[1]}*60+${hms[2]} -
tzoff - now - 1
) % 86400)).${nsslp:1}
$quiet || printf 'sleep %ss, -> %(%c)T\n' $slp $((now+${slp%.*}+1))
sleep $slp
}
Setelah menentukan dua variabel hanya-baca , TIMER_LIST_OFFSET
dan TIMER_LIST_SKIP
, fungsi tersebut akan mengakses dengan sangat cepat file variabel /proc/timer_list
untuk menghitung waktu tidur:
Fungsi tes kecil
tstSleepUntilHires () {
local now next last
printf -v next "%(%H:%M:%S)T" $((${EPOCHREALTIME%.*}+1))
sleepUntilHires $next
date -f - +%F-%T.%N < <(echo now;sleep .92;echo now)
printf -v next "%(%H:%M:%S)T" $((${EPOCHREALTIME%.*}+1))
sleepUntilHires $next
date +%F-%T.%N
}
Mungkin membuat sesuatu seperti:
sleep 0.244040s, -> Wed Apr 22 10:34:39 2020
2020-04-22-10:34:39.001685312
2020-04-22-10:34:39.922291769
sleep 0.077012s, -> Wed Apr 22 10:34:40 2020
2020-04-22-10:34:40.004264869
- Di awal detik berikutnya,
- mencetak waktu, lalu
- tunggu 0,92 detik, lalu
- mencetak waktu, lalu
- hitung 0,07 detik tersisa, ke detik berikutnya
- tidur 0,07 detik, lalu
- waktu cetak.
Peduli untuk tidak mencampur $EPOCHSECOND
dan $EPOCHREALTIME
!
Baca peringatan saya tentang perbedaan antara $EPOCHSECOND
dan$EPOCHREALTIME
Fungsi ini digunakan $EPOCHREALTIME
jadi jangan gunakan $EPOCHSECOND
untuk menetapkan detik berikutnya :
Contoh masalah: Mencoba mencetak waktu berikutnya dibulatkan oleh 2 detik:
for i in 1 2;do
printf -v nextH "%(%T)T" $(((EPOCHSECONDS/2)*2+2))
sleepUntilHires $nextH
IFS=. read now musec <<<$EPOCHREALTIME
printf "%(%c)T.%s\n" $now $musec
done
Dapat menghasilkan:
sleep 0.587936s, -> Wed Apr 22 10:51:26 2020
Wed Apr 22 10:51:26 2020.000630
sleep 86399.998797s, -> Thu Apr 23 10:51:26 2020
^C