Como esta pregunta se hizo hace 4 años, esta primera parte se refiere a versiones antiguas de bash:
Última edición: miércoles 22 de abril de 2020, algo entre las 10:30 y las 10h: 55 (importante para las muestras de lectura)
Método general (¡Evite los tenedores inútiles!)
(Nota: este uso del método date -f
! Wich hay POSIX y no hacer el trabajo bajo MacOS Si en Mac, ir a mi puraintentofunción )
Para reducir forks
, en lugar de ejecutar date
dos veces, prefiero usar esto:
Muestra inicial simple
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
donde tomorrow 21:30
podría ser reemplazado por cualquier tipo de fecha y formato reconocido por date
, en el futuro.
Con alta precisión (nanosec)
Casi lo mismo:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Alcanzando la próxima vez
Para alcanzar el siguienteHH:MM
significado hoy si es posible, mañana si es demasiado tarde:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Esto funciona bajo intento, ksh y otras carcasas modernas, pero debes usar:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
bajo conchas más ligeras comoceniza o guión.
Puro intento camino, sin tenedor !!
¡Probado en MacOS!
Escribí uno de dos pequeñas funciones: sleepUntil
ysleepUntilHires
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)
Como las nuevas versiones de bash ofrecen una printf
opción para recuperar la fecha, para esta nueva forma de dormir hasta HH: MM sin usar date
o cualquier otra bifurcación, he construido un pocointentofunción. Aquí está:
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
}
Entonces:
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
Si el objetivo es antes, este dormirá hasta mañana:
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
Hola tiempo con intento bajo GNU / Linux
Reciente intento, a partir de la versión 5.0 agregue una nueva $EPOCHREALTIME
variable con microsegundos. De esto hay una sleepUntilHires
función.
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
}
Tenga en cuenta: este uso read -t
está integrado, en lugar de sleep
. Desafortunadamente, esto no funcionará cuando se ejecute en segundo plano, sin TTY real. Siéntase libre de reemplazar read -t
por sleep
si planea ejecutar esto en scripts en segundo plano ... (Pero para el proceso en segundo plano, considere usar cron
y / o en at
lugar de todo esto)
Omita el siguiente párrafo para las pruebas y advertencias $ËPOCHSECONDS
.
¡El kernel reciente evita el uso /proc/timer_list
por parte del usuario!
Bajo el reciente kernel de Linux, encontrará un archivo de variables llamado `/ proc / timer_list` donde puede leer un` offset` y una variable `now`, en ** nanosegundos **. Por lo tanto, podemos calcular el tiempo de sueño para alcanzar el * máximo * tiempo deseado.
(Escribí esto para generar y rastrear eventos específicos en archivos de registro muy grandes, que contienen mil líneas por un segundo).
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
}
Después de definir dos variables de solo lectura , TIMER_LIST_OFFSET
y TIMER_LIST_SKIP
, la función accederá muy rápidamente al archivo de variables /proc/timer_list
para calcular el tiempo de suspensión:
Pequeña función de prueba
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
}
Puede representar algo como:
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
- Al comienzo del siguiente segundo,
- tiempo de impresión, entonces
- espere 0.92 segundos, luego
- tiempo de impresión, entonces
- calcular 0.07 segundos restantes, al siguiente segundo
- dormir 0.07 segundos, luego
- tiempo de impresión.
¡Cuidado de no mezclar $EPOCHSECOND
y $EPOCHREALTIME
!
Lea mi advertencia sobre la diferencia entre $EPOCHSECOND
y$EPOCHREALTIME
Esta función se usa, $EPOCHREALTIME
así que no la use $EPOCHSECOND
para establecer el siguiente segundo :
Problema de muestra: Intentando imprimir el tiempo siguiente redondeado en 2 segundos:
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
Puede producir:
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