Поскольку этот вопрос был задан 4 года назад, первая часть касается старых версий bash:
Последнее изменение: среда, 22 апреля 2020 г., что-то между 10:30 и 10:55 (важно для чтения образцов)
Общий метод (Избегайте бесполезных вилок!)
(Примечание: этот метод используется date -f
не в POSIX и не работает под MacOS! Если под Mac, перейдите к моему чистомутрепатьфункция )
Чтобы уменьшить forks
, вместо того, чтобы запускать date
два раза, я предпочитаю использовать это:
Простой стартовый образец
sleep $(($(date -f - +%s- <<< $'tomorrow 21:30\nnow')0))
где tomorrow 21:30
может быть заменен любой датой и форматом, распознаваемым date
в будущем.
С высокой точностью (наносекунд)
Почти то же самое:
sleep $(bc <<<s$(date -f - +'t=%s.%N;' <<<$'07:00 tomorrow\nnow')'st-t')
Достигнув следующего раза
Для достижения следующегоHH:MM
значения сегодня, если возможно, завтра, если слишком поздно:
sleep $((($(date -f - +%s- <<<$'21:30 tomorrow\nnow')0)%86400))
Это работает под трепать, кш и другие современные оболочки, но вы должны использовать:
sleep $(( ( $(printf 'tomorrow 21:30\nnow\n' | date -f - +%s-)0 )%86400 ))
под более легкими снарядами, такими какясень или рывок.
Чистый трепать Кстати, вилки нет !!
Проверено под MacOS!
Я написал одну две маленькие функции: sleepUntil
иsleepUntilHires
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)
Поскольку новые версии bash предлагают printf
возможность получения даты, для этого нового способа засыпать до ЧЧ: ММ без использования date
или какой-либо другой вилки, я немного построилтрепатьфункция. Вот:
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
}
Затем:
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
Если цель раньше, это будет спать до завтра:
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 с трепать под GNU / Linux
Недавние трепать, с версии 5.0 добавлена новая $EPOCHREALTIME
переменная с микросекундами. От этого есть sleepUntilHires
функция.
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
}
Обратите внимание: это read -t
встроенное использование вместо sleep
. К сожалению, это не сработает при работе в фоновом режиме без реального TTY. Не стесняйтесь заменить read -t
на, sleep
если вы планируете запускать это в фоновых сценариях ... (Но для фонового процесса рассмотрите возможность использования cron
и / или at
вместо всего этого)
Пропустите следующий абзац, чтобы узнать о тестах и предупреждениях $ËPOCHSECONDS
!
Последнее ядро не используется /proc/timer_list
пользователем !!
В недавнем ядре Linux вы найдете файл переменных с именем `/ proc / timer_list`, в котором вы можете прочитать переменную` offset` и `now` за ** наносекунды **. Таким образом, мы можем вычислить время сна, чтобы достичь * самого верхнего * желаемого времени.
(Я написал это для генерации и отслеживания конкретных событий в очень больших файлах журнала, содержащих тысячу строк за одну секунду).
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
}
После определения двух переменных, доступных только для чтения , TIMER_LIST_OFFSET
и TIMER_LIST_SKIP
функция очень быстро получит доступ к файлу переменных /proc/timer_list
для вычисления времени сна:
Маленькая тестовая функция
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
}
Может отображать что-то вроде:
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
- В начале следующей секунды
- время печати, тогда
- подождите 0,92 секунды, затем
- время печати, тогда
- вычислить 0,07 секунды до следующей секунды
- спать 0,07 секунды, затем
- время печати.
Не смешивайте $EPOCHSECOND
и $EPOCHREALTIME
!
Прочтите мое предупреждение о разнице между $EPOCHSECOND
и$EPOCHREALTIME
Эта функция используется, $EPOCHREALTIME
поэтому не используйте ее $EPOCHSECOND
для установки следующей секунды :
Пример проблемы: попытка напечатать время с округлением на 2 секунды:
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
Может производить:
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