Цикл времени в оболочке
Недавно я начал изучать оболочку script, поэтому я не знаю много о ней.
Я пытаюсь найти пример цикла, основанного на времени, но не имеющего удачи.
Я хочу запустить цикл за определенное количество времени, скажем, 1 час. Таким образом, цикл работает в течение часа, а затем автоматически завершается.
Изменить: этот цикл будет работать непрерывно без сна, поэтому условие цикла должно основываться на времени начала цикла и текущем времени, а не во сне.
Ответы
Ответ 1
Лучший способ сделать это - использовать переменную $SECONDS, которая имеет счет времени, в течение которого работает script (или shell). В приведенном ниже примере показано, как запустить цикл while в течение 3 секунд.
#! /bin/bash
end=$((SECONDS+3))
while [ $SECONDS -lt $end ]; do
# Do what you want.
:
done
Ответ 2
Caveat. Все решения в этом ответе - кроме ksh
one - могут вернуться до (но не включая) 1 секунду раньше, так как они основаны на счетчике целых секунд, что авансы, основанные на часах реального времени (системы), а не на основе того, когда началось выполнение кода.
bash
, ksh
, zsh
, используя специальную переменную оболочки $SECONDS
:
Немного упрощенная версия ответа @bsravanin.
Вкратце говоря, $SECONDS
содержит количество секунд, прошедших до сих пор в script.
В bash
и zsh
вы получаете целые секунды, продвигающиеся по импульсу системных (в реальном времени) часов, т.е. подсчет за кулисами действительно не начинается с 0
(!), но при любом с момента последнего полного второго дня после запуска script или переменной SECONDS
было reset.
В отличие от этого, ksh
работает так, как и следовало ожидать: подсчет действительно начинается с 0
, когда вы reset $SECONDS
; кроме того, $SECONDS
сообщает дробные секунды в ksh
.
Следовательно, единственная оболочка, в которой это решение работает разумно предсказуемо и точно, ksh
. Тем не менее для грубых измерений и таймаутов он может по-прежнему использоваться в bash
и zsh
.
Примечание. Следующая строка использует строку bash
shebang; просто подставляя ksh
или zsh
для bash
, запустим script с этими оболочками.
#!/usr/bin/env bash
secs=3600 # Set interval (duration) in seconds.
SECONDS=0 # Reset $SECONDS; counting of seconds will (re)start from 0(-ish).
while (( SECONDS < secs )); do # Loop until interval has elapsed.
# ...
done
Решение для оболочек только для POSIX-функций, таких как sh
(dash
) на Ubuntu ($SECONDS
не совместимо с POSIX)
Убрана версия ответа @dcpomero.
Используется время epoch, возвращаемое date +%s
(секунды, прошедшие с 1 января 1970 года) и синтаксис POSIX для условного.
Предостережение: date +%s
сам (в частности, формат %s
) не совместим с POSIX, но он будет работать (по крайней мере) Linux, FreeBSD и OSX.
#!/bin/sh
secs=3600 # Set interval (duration) in seconds.
endTime=$(( $(date +%s) + secs )) # Calculate end time.
while [ $(date +%s) -lt $endTime ]; do # Loop until interval has elapsed.
# ...
done
Ответ 3
Вы можете попробовать это
starttime = `date +%s`
while [ $(( $(date +%s) - 3600 )) -lt $starttime ]; do
done
где 'date +%s'
задает текущее время в секундах.
Ответ 4
date +%s
даст вам секунды с эпохи, поэтому что-то вроде
startTime = `date +%s`
timeSpan = #some number of seconds
endTime = timeSpan + startTime
while (( `date +%s` < endTime )) ; do
#code
done
Возможно, вам понадобятся некоторые изменения, так как мой bash ржавый
Ответ 5
Вы можете изучить параметр -d
date
.
Ниже приведен фрагмент оболочки script для иллюстрации. Это похоже на другие ответы, но может быть более полезным в разных сценариях.
# set -e to exit if the time provided by argument 1 is not valid for date.
# The variable stop_date will store the seconds since 1970-01-01 00:00:00
# UTC, according to the date specified by -d "$1".
set -e
stop_date=$(date -d "$1" "+%s")
set +e
echo -e "Starting at $(date)"
echo -e "Finishing at $(date -d "$1")"
# Repeat the loop while the current date is less than stop_date
while [ $(date "+%s") -lt ${stop_date} ]; do
# your commands that will run until stop_date
done
Затем вы можете вызвать script разными способами, которые понимает дата:
$ ./the_script.sh "1 hour 4 minutes 3 seconds"
Starting at Fri Jun 2 10:50:28 BRT 2017
Finishing at Fri Jun 2 11:54:31 BRT 2017
$ ./the_script.sh "tomorrow 8:00am"
Starting at Fri Jun 2 10:50:39 BRT 2017
Finishing at Sat Jun 3 08:00:00 BRT 2017
$ ./the_script.sh "monday 8:00am"
Starting at Fri Jun 2 10:51:25 BRT 2017
Finishing at Mon Jun 5 08:00:00 BRT 2017