Da diese Frage vor 4 Jahren gestellt wurde, betrifft dieser erste Teil alte Bash-Versionen:
Letzte Änderung: Mi 22. April 2020, etwas zwischen 10:30 und 10h: 55 (Wichtig zum Lesen von Proben)
Allgemeine Methode (Vermeiden Sie nutzlose Gabeln!)
(Nota: Diese Methode verwendet date -f
kein POSIX und funktioniert nicht unter MacOS! Wenn unter Mac, gehe zu meinem reinenBashFunktion )
Um zu reduzieren forks
, anstatt date
zweimal zu laufen , bevorzuge ich Folgendes:
Einfache Startprobe
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
wo tomorrow 21:30
könnte in Zukunft durch jede Art von Datum und Format ersetzt werden, die von anerkannt date
werden.
Mit hoher Präzision (Nanosec)
Fast gleich:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Das nächste Mal erreichen
Um heute, wenn möglich, die nächsteHH:MM
Bedeutung zu erreichen, morgen, wenn es zu spät ist:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Das funktioniert unter Bash, ksh und andere moderne Muscheln, aber Sie müssen verwenden:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
unter leichteren Muscheln wieAsche oder Strich.
Rein Bash übrigens keine Gabel !!
Unter MacOS getestet!
Ich schrieb eine zwei kleine Funktionen: sleepUntil
undsleepUntilHires
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)
Da neue Versionen von Bash eine printf
Option zum Abrufen des Datums bieten , habe ich für diese neue Art des Schlafens bis HH: MM ohne Verwendung date
oder mit einer anderen Gabel ein wenig gebautBashFunktion. Hier ist es:
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
}
Dann:
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
Wenn das Ziel vorher ist, wird dies bis morgen schlafen:
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
HiRes Zeit mit Bash unter GNU / Linux
Kürzlich Bash, ab Version 5.0 neue $EPOCHREALTIME
Variable mit Mikrosekunden hinzufügen . Daraus ergibt sich eine sleepUntilHires
Funktion.
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
}
Bitte beachten Sie: Diese Verwendung read -t
ist anstelle von integriert sleep
. Leider funktioniert dies nicht, wenn Sie im Hintergrund ohne echte TTY ausgeführt werden. Fühlen Sie sich frei zu ersetzen read -t
durch , sleep
wenn Sie planen , diese Scripts im Hintergrund laufen zu lassen ... (Aber für Hintergrundprozess, sollten Sie mit cron
und / oder at
anstelle von alledem)
Überspringen Sie den nächsten Absatz für Tests und Warnungen $ËPOCHSECONDS
!
Aktuelle Kernel vermeiden /proc/timer_list
von Benutzer zu verwenden!
Unter dem aktuellen Linux-Kernel finden Sie eine Variablendatei mit dem Namen "/ proc / timer_list", in der Sie eine "Offset" - und eine "Now" -Variable in ** Nanosekunden ** lesen können. Wir können also die Schlafzeit berechnen, um die * höchste * gewünschte Zeit zu erreichen.
(Ich habe dies geschrieben, um bestimmte Ereignisse in sehr großen Protokolldateien zu generieren und zu verfolgen, die für eine Sekunde tausend Zeilen enthalten.)
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
}
Nach dem Definieren von zwei schreibgeschützten Variablen TIMER_LIST_OFFSET
und TIMER_LIST_SKIP
greift die Funktion sehr schnell auf die Variablendatei zu, um die Ruhezeit /proc/timer_list
zu berechnen:
Kleine Testfunktion
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
}
Kann so etwas wie rendern:
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
- At begin of next second,
- print time, then
- wait 0.92 seccond, then
- print time, then
- compute 0.07 seconds left, to next second
- sleep 0.07 seconds, then
- print time.
Care to not mix $EPOCHSECOND
and $EPOCHREALTIME
!
Read my warning about difference between $EPOCHSECOND
and $EPOCHREALTIME
This function use $EPOCHREALTIME
so don't use $EPOCHSECOND
for establishing next second:
Sample issue: Trying to print time next rounded by 2 seconds:
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
May produce:
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