Попробуйте watch
команда.
Usage: watch [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>]
[--no-title] [--version] <command>`
Так, чтобы:
watch -n1 command
будет выполнять команду каждую секунду (хорошо, технически, всех секунду плюс время, для которого требуется command
работать как watch
(по крайней мере, procps
и busybox
реализации), просто спит вторые промежуточные два выполнения command
), навсегда.
Вы хотели бы передать команду exec
вместо sh -c
, использовать -x
опция:
watch -n1 -x command
На macOS можно добраться watch
от портов Mac:
port install watch
Или можно получить его от Домашнего пива:
brew install watch
Вы могли получить эту рекурсивную функцию:
#!/bin/bash
ininterval () {
delay=$1
shift
$*
sleep $delay
ininterval $delay $*
}
или добавьте:
ininterval $*
и назовите сценарий.
Как упомянуто gbrandt, если watch
команда доступна, определенно используйте ее. Некоторым системам Unix, однако, не установили его по умолчанию (по крайней мере, они не делают, где я работаю).
Вот другое решение с немного отличающимся синтаксисом и выводом (работы в Bash и SH):
while [ 1 ] ; do
<cmd>
sleep <x>
echo ">>>>>>>>>>>>>" `date` ">>>>>>>>>>>>>>"
done
Править: Я удалил некоторых "." в последнем операторе эха... пережиток с моих дней Perl ;)
while [ 1 ]
только работы, потому что 1 рассматривается как строку, точно так же, как while [ -n 1 ]
. while [ 0 ]
или while [ jeff ]
сделал бы то же самое. while true
имеет намного больше смысла.
– Mikel
05.04.2011, 13:19
#!/usr/bin/env perl
# First argument is number of seconds to sleep between repeats, remaining
# arguments give the command to repeat forever.
$sleep = shift;
$cmd = join(' ', @ARGV);
while(1) {
system($cmd);
sleep($sleep);
}
Хотеть попробовать это (Bash)?
forever () {
TIMES=shift;
SLEEP=shift;
if [ "$TIMES" = "-1" ]; then
while true;
do
$@
sleep $SLEEP
done
else
repeat "$TIMES" $@
fi; }
В bash
:
bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; done'
(echo
мог быть заменен любой командой...
Или в perl
:
perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"}'
Где print "I will not automate this punishment in absurdum.\n"
мог быть заменен "любой" командой, окруженной обратными галочками (').
И для паузы, добавьте a sleep
оператор в для цикла:
bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; sleep 1; done'
и
perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"; sleep 1}'
while [ 0 ]
плохой путь состоит в том, чтобы записать это. Это означает 0
строка с длиной> 0. while [ 1 ]
или while [ jeff ]
сделал бы то же самое. Лучше записать while true
.
– Mikel
05.04.2011, 13:17
Bash
while
+ sleep
:
while true
do
echo "Hi"
sleep 1
done
Вот то же самое как краткая острота (Из комментариев ниже):
while sleep 1; do echo "Hi"; done
Использование ;
разделить команды и использование sleep 1
для while
тест, так как это всегда возвращает true. Можно поместить больше команд в цикл - просто разделяют их с ;
sleep
не всегда возвращает true. Ī ̲ использовал такие циклы (хотя с более длинной задержкой) а именно, потому что существует способ завершить его корректно с уничтожением спящего процесса.
– Incnis Mrsi
13.09.2015, 01:53
Это решение работает в MacOSX 10.7. Это работает замечательно.
bash -c 'while [ 0 ]; do \
echo "I will not automate this punishment in absurdum."; done'
В моем случае
bash -c 'while [ 0 ]; do ls; done'
или
bash -c 'while [ 0 ]; do mv "Desktop/* Documents/Cleanup"; done'
очищать мой рабочий стол постоянно.
while [ 0 ]
нечетный путь состоит в том, чтобы записать бесконечный цикл; это работает потому что test
команда (также известный как [
) рассматривает непустую строку как верную. while : ; do ... ; done
более идиоматично, или если Вы предпочитаете, чтобы можно было использовать while true ; do ... ; done
.
– Keith Thompson
17.01.2012, 10:11
Быстрый, грязный и вероятно опасный для начальной загрузки, но если Вы предприимчивы и знаете то, что Вы делаете, помещает это в repeat.sh
и chmod 755
это,
while true
do
eval $1
sleep $2
done
Вызовите его с ./repeat.sh <command> <interval>
Мой смысл spidey говорит, что это - вероятно, злой способ сделать это, действительно ли мой смысл spidey является правильным?
Если Ваше намерение не состоит в том, чтобы отобразить сообщение на Ваш экран, и если бы Вы могли бы позволить себе повторить, что задание с точки зрения минут, crontab, возможно, было бы Вашим лучшим инструментом. Например, если бы Вы хотите выполнить свою команду каждую минуту, Вы записали бы что-то вроде этого в Вашем crontab
файл:
* * * * * my_precious_command
Проверьте учебное руководство для дальнейшего примера. Кроме того, можно установить синхронизации легко с помощью Генератора кода Crontab.
Одна проблема, которую до сих пор, имеют все ответы, отправленные, состоит в том, что время, команда выполняется, может дрейфовать. Например, если Вы делаете a sleep 10
между командами и командой занимает 2 секунды для выполнения, затем она собирается работать каждые 12 секунд; если требуется переменное количество времени для выполнения, то за длительный срок время, когда это работает, может быть непредсказуемым.
Это могло бы быть, что Вы хотите; если так, используйте одно из других решений, или используйте этого, но упростите sleep
звонить.
Для одноминутного разрешения задания крона будут работать в требуемое время, независимо от того, сколько времени каждая команда берет. (На самом деле новое задание крона запустится, даже если предыдущий будет все еще работать.)
Вот простой сценарий Perl, который спит до следующего интервала так например, с интервалом 10 секунд команда могла бы работать в 12:34:00, 12:34:10, 12:34:20, и т.д., даже если сама команда занимает несколько секунд. Если команда выполняет больше, чем interval
секунды, следующий интервал будет пропущен (в отличие от крона). Интервал вычисляется относительно эпохи, таким образом, интервал 86 400 секунд (1 день) выполнит в полночь UTC.
#!/usr/bin/perl
use strict;
use warnings;
if (scalar @ARGV < 2) {
die "Usage: $0 seconds command [args...]\n";
}
$| = 1; # Ensure output appears
my($interval, @command) = @ARGV;
# print ">>> interval=$interval command=(@command)\n";
while (1) {
print "sleep ", $interval - time % $interval, "\n";
sleep $interval - time % $interval;
system @command; # TODO: Handle errors (how?)
}
while :; do sleep 1m & command; wait; done
– math
14.09.2017, 16:53
wait
будет ожидать всех их). Это является закрепляемым путем изменения wait
кому: wait $!
, где $!
PID sleep
процесс. Отправьте это как ответ, и я буду upvote он. Но это действительно производит некоторый посторонний вывод в интерактивной оболочке.
– Keith Thompson
14.09.2017, 23:59
... Интересно, насколько сложные решения могут быть созданы при решении этой проблемы.
Это может быть настолько легко...
open /etc/crontab
помещенный там 1 следующая строка в конец файла как:
*/NumberOfSeconds * * * * user /path/to/file.sh
Если Вы хотите выполнить что-то каждая 1 секунда, просто поместите там:
*/60 * * * * root /path/to/file.sh
where that file.sh could be chmod 750 /path/to/file.sh
и в котором file.sh должен быть:
#!/bin/bash
#What does it do
#What is it runned by
your code or commands
и это - все!
Приятного отдыха!
Для повторного выполнения команды в консоли, я обычно выполняю что-то вроде этого:
while true; do (run command here); done
Это работает на несколько команд также, например, для отображения постоянно обновляющих часов в консоли:
while true; do clear; date; sleep 1; done
Это - просто более короткая версия другого while+sleep
ответы при выполнении этого вида задач часто как распорядок дня, с помощью этого, сохраняют Вас от ненужных нажатий клавиш, и если Ваша командная строка начинает получать более долгое понимание, что этот немного легче. Но этот запускает со сна сначала.
Это обычно полезно, если необходимо следовать, что-то имеет короткий вывод как загрузка машины:
while sleep 1; do uptime; done
while clear; do date; command;sleep 5; done
– Johan
15.03.2013, 11:12
Bash и некоторые его родственные оболочки имеет удобное (( ... ))
нотация, где арифметические выражения могут быть оценены.
Таким образом, поскольку ответ на Ваш третий вызов, где оба повторный счет и задержка между каждым повторением должны настраиваться, вот является одним способом сделать это:
repeat=10
delay=1
i=0
while (( i++ < repeat )); do
echo Repetition $i
sleep $delay
done
Этот ответ также страдает от дрейфа синхронизации, охваченного в ответе Keith.
Вы могли запустить скрипт от init (добавляющий строку к/etc/inittab). Этот сценарий должен выполнить Вашу команду, сон в течение времени, Вы хотите ожидать, пока не запущено скрипт снова и выйти из него. Init запустит Ваш сценарий снова после выхода.
Что, если у нас были оба?
Вот идея: только с "интервалом" это повторяется навсегда. С "интервалом" и "времена", это повторяет это количество раз, разделенное "интервалом".
Использование:
$ loop [interval [times]] command
Так, алгоритм будет:
Поэтому:
loop() {
local i=2 t=1 cond
[ -z ${1//[0-9]/} ] && i=$1 && shift
[ -z ${1//[0-9]/} ] && t=$1 && shift && cond=1
while [ $t -gt 0 ]; do
sleep $i
[ $cond ] && : $[--t]
$@
done
}
sleep
действительно принимает их.
– Baronsed
12.11.2013, 00:37
#! /bin/sh
# Run all programs in a directory in parallel
# Usage: run-parallel directory delay
# Copyright 2013 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution
if [ $# -eq 0 ]
then
echo
echo "run-parallel by Marc Perkel"
echo
echo "This program is used to run all programs in a directory in parallel"
echo "or to rerun them every X seconds for one minute."
echo "Think of this program as cron with seconds resolution."
echo
echo "Usage: run-parallel [directory] [delay]"
echo
echo "Examples:"
echo " run-parallel /etc/cron.20sec 20"
echo " run-parallel 20"
echo " # Runs all executable files in /etc/cron.20sec every 20 seconds or 3 times a minute."
echo
echo "If delay parameter is missing it runs everything once and exits."
echo "If only delay is passed then the directory /etc/cron.[delay]sec is assumed."
echo
echo 'if "cronsec" is passed then it runs all of these delays 2 3 4 5 6 10 12 15 20 30'
echo "resulting in 30 20 15 12 10 6 5 4 3 2 executions per minute."
echo
exit
fi
# If "cronsec" is passed as a parameter then run all the delays in parallel
if [ $1 = cronsec ]
then
$0 2 &
$0 3 &
$0 4 &
$0 5 &
$0 6 &
$0 10 &
$0 12 &
$0 15 &
$0 20 &
$0 30 &
exit
fi
# Set the directory to first prameter and delay to second parameter
dir=$1
delay=$2
# If only parameter is 2,3,4,5,6,10,12,15,20,30 then automatically calculate
# the standard directory name /etc/cron.[delay]sec
if [[ "$1" =~ ^(2|3|4|5|6|10|12|15|20|30)$ ]]
then
dir="/etc/cron.$1sec"
delay=$1
fi
# Exit if directory doesn't exist or has no files
if [ ! "$(ls -A $dir/)" ]
then
exit
fi
# Sleep if both $delay and $counter are set
if [ ! -z $delay ] && [ ! -z $counter ]
then
sleep $delay
fi
# Set counter to 0 if not set
if [ -z $counter ]
then
counter=0
fi
# Run all the programs in the directory in parallel
# Use of timeout ensures that the processes are killed if they run too long
for program in $dir/* ; do
if [ -x $program ]
then
if [ "0$delay" -gt 1 ]
then
timeout $delay $program &> /dev/null &
else
$program &> /dev/null &
fi
fi
done
# If delay not set then we're done
if [ -z $delay ]
then
exit
fi
# Add delay to counter
counter=$(( $counter + $delay ))
# If minute is not up - call self recursively
if [ $counter -lt 60 ]
then
. $0 $dir $delay &
fi
# Otherwise we're done
Для ограничения времени выполнения нет никаких ветвлений! Только встроенный используются.
Для этого я использую read
встроенная функция вместо sleep
. Unfortunely это не будет работать с notty сессиями.
repeat
"согласно просьбе:repeat () {
local repeat_times=$1 repeat_delay=$2 repeat_foo repeat_sleep
read -t .0001 repeat_foo
if [ $? = 1 ] ;then
repeat_sleep() { sleep $1 ;}
else
repeat_sleep() { read -t $1 repeat_foo; }
fi
shift 2
while ((repeat_times)); do
((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
"${@}"
((repeat_times))&& ((10#${repeat_delay//.})) &&
repeat_sleep $repeat_delay
done
}
Мало теста с заключенными в кавычки строками:
repeat 3 0 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.
repeat -1 .5 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:14:14, Hello Guy.
Now: 15:14:14, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:18, Hello Guy.
Now: 15:14:18, Hello Guy.
^C
Под недавними ядрами Linux существует procfile /proc/timer_list
содержа информацию времени в наносекундах.
Если Вы хотите выполнить команду точно однажды вторым, Ваша команда должна закончиться в меньше, чем секунда! И оттуда, Вы имеете к sleep
только остальная часть текущей секунды.
Если задержка более важна, и Ваша команда не требует значительного времени, Вы могли:
command=(echo 'Hello world.')
delay=10
while :;do
printf -v now "%(%s)T" -1
read -t $(( delay-(now%delay) )) foo
${command[@]}
done.
Но если Ваша цель состоит в том, чтобы получить более прекрасную гранулярность, Вы имеете к:
Для этого я записал немного функции удара:
# bash source file for nano wait-until-next-second
mapfile </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
((_c+=${#_timer_list[_i]}))
[[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
[[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ
waitNextSecondHires() {
local nsnow nsslp
read -N$TIMER_LIST_READ nsnow </proc/timer_list
nsnow=${nsnow%% nsecs*}
nsnow=$((${nsnow##* }+TIMER_LIST_OFFSET))
nsslp=$((2000000000-10#${nsnow:${#nsnow}-9}))
read -t .${nsslp:1} foo
}
После определения источника их Вы могли:
command=(echo 'Hello world.')
while :;do
waitNextSecondHires
${command[@]}
done.
выполненный ${command[@]}
непосредственно на командной строке, чем выдерживают сравнение с
command=(eval "echo 'Hello world.';sleep .3")
while :;do
waitNextSecondHires
${command[@]}
done.
это должно дать точно тот же результат.
repeat
"согласно просьбе:Вы могли получить это:
mapfile </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
((_c+=${#_timer_list[_i]}))
[[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
[[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ
repeat_hires () {
local repeat_times=$1 repeat_delay=$2 repeat_foo repeat_sleep repeat_count
read -t .0001 repeat_foo
if [ $? = 1 ] ;then
repeat_sleep() { sleep $1 ;}
else
repeat_sleep() { read -t $1 repeat_foo; }
fi
shift 2
printf -v repeat_delay "%.9f" $repeat_delay
repeat_delay=${repeat_delay//.}
read -N$TIMER_LIST_READ nsnow </proc/timer_list
nsnow=${nsnow%% nsec*}
started=${nsnow##* }
while ((repeat_times)); do
((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
"${@}"
((repeat_times)) && ((10#$repeat_delay)) && {
read -N$TIMER_LIST_READ nsnow </proc/timer_list
nsnow=${nsnow%% nsec*}
nsnow=${nsnow##* }
(( (nsnow - started) / 10#$repeat_delay - repeat_count++ )) &&
printf >&2 "WARNING: Command '%s' too long for %f delay.\n" \
"${*}" ${repeat_delay:0:${#repeat_delay}-9
}.${repeat_delay:${#repeat_delay}-9}
printf -v sleep "%010d" $((
10#$repeat_delay - ( ( nsnow - started ) % 10#$repeat_delay ) ))
repeat_sleep ${sleep:0:${#sleep}-9}.${sleep:${#sleep}-9}
}
done
}
Затем попробуйте его:
time repeat_hires 21 .05 sh -c 'date +%s.%N;sleep .01'
1480867565.152022457
1480867565.201249108
1480867565.251333284
1480867565.301224905
1480867565.351236725
1480867565.400930482
1480867565.451207075
1480867565.501212329
1480867565.550927738
1480867565.601199721
1480867565.651500618
1480867565.700889792
1480867565.750963074
1480867565.800987954
1480867565.853671458
1480867565.901232296
1480867565.951171898
1480867566.000917199
1480867566.050942638
1480867566.101171249
1480867566.150913407
real 0m1.013s
user 0m0.000s
sys 0m0.016s
time repeat_hires 3 .05 sh -c 'date +%s.%N;sleep .05'
1480867635.380561067
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.486503367
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.582332617
real 0m0.257s
user 0m0.000s
sys 0m0.004s
read -t
встроенное, в то время как sleep
не. Это могло иметь краевой эффект (т.е. совершающий нападки [key:return] прерывают бесшумно сон), но это можно было рассматривать путем тестирования $foo
– F. Hauri
29.01.2014, 19:34
Я думаю, что весь ответ здесь до сих пор является или слишком замысловатым, или вместо этого отвечает на другой вопрос:
Реальный вопрос был:
Это две совсем других вещи, когда команда занимает время для окончания.
Возьмите, например, сценарий foo.sh
(притворитесь, что это - программа, которая занимает несколько секунд для завершения).
#!/bin/bash
# foo.sh
echo `date +"%H:%M:%S"` >> output.txt;
sleep 2.5;
# ---
Вы хотите выполнить это каждую секунду, и большинство предложило бы watch -n1 ./foo.sh
, или while sleep 1; do ./foo.sh; done
. Однако это дает вывод:
15:21:20
15:21:23
15:21:27
15:21:30
15:21:34
Который точно не выполняется каждую секунду. Даже с -p
флаг, как man watch
страница предлагает, мог бы решить это, результатом является то же.
Простой способ выполнить желаемую задачу, который некоторое касание к, состоит в том, чтобы выполнить команду в фоновом режиме. Другими словами:
while sleep 1; do (./foo.sh &) ; done
И это - все, которое существует к нему.
Вы могли выполнить его каждые 500 мс с sleep 0.5
, или что имеет Вас.
while :; do sleep 1 & ./foo.sh; wait; done
– math
14.09.2017, 16:57
кронтаб: * * * script.sh
script.sh:
Я завел, создавая вариант на ответе Swalog. С его вы должны были подождать x секунды для первой итерации, я также бегаю на переднем плане, так что ...
./foo.sh;while sleep 1; do (./foo.sh) ; done
until ! sleep 60; do echo $(date); command; command; command; done
у меня работает.
Вы можете получить мощность от интерпретатора Python из оболочки.
python3 -c "import time, os
while True:
os.system('your command')
time.sleep(5)
заменить пять в любое время (сек )вы хотите.
Внимание :при возврате используйте SHIFT+ENTER для возврата ввода в оболочку. И не забудьте набрать 4 ПРОБЕЛ отступ в каждой строке в цикле while.
С zsh
и реализацией sleep
, которая принимает аргументы с плавающей запятой -:
typeset -F SECONDS=0 n=0
repeat 100 {cmd; sleep $(((n+=3) - SECONDS))}
Или дляforever
:
for ((;;)) {cmd; sleep $(((n+=3) - SECONDS))}
Если ваш sleep
не поддерживает числа с плавающей запятой, вы всегда можете переопределить его как оболочку вокруг встроенной функции zsh
zselect
:
zmodload zsh/zselect
sleep() zselect -t $((($1 * 100) | 0))
while true; do X; sleep Y; done
- Это - путь лучше. – Adam Matan 16.05.2011, 14:14cmdwatch
на FreeBSD (от портов:sysutils/cmdwatch
). – Ouki 25.03.2014, 23:29