Повторите команду Unix каждый x секунды навсегда

Если Вы хотите программу, которая просто разделяет терминал ¹, существует splitvt. Существуют программы, которые разделяют терминал и делают много другого материала кроме того, такого как Экран, Tmux, Emacs, …

¹ Это - терминал, который Вы разделяете, не оболочка.

495
02.11.2019, 19:18
25 ответов

Попробуйте 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
632
27.01.2020, 19:28
  • 1
    можно использовать MacPorts для установки его. порт sudo устанавливает –   17.02.2009, 02:27
  • 2
    Также доступный в домашнем пиве (варят часы установки). –  Lyle 13.05.2011, 00:45
  • 3
    +1 Для нового мощного инструмента. Я привык для while true; do X; sleep Y; done - Это - путь лучше. –  Adam Matan 16.05.2011, 14:14
  • 4
    с этим инструментом (на Ubuntu, по крайней мере) состоит в том, что это вызывает полный экран, поэтому если я вывожу некоторую периодическую информацию, я теряю предыдущую информацию –  scorpiodawg 12.10.2012, 04:00
  • 5
    Это называют cmdwatch на FreeBSD (от портов: sysutils/cmdwatch). –  Ouki 25.03.2014, 23:29

Вы могли получить эту рекурсивную функцию:

#!/bin/bash
ininterval () {
    delay=$1
    shift
    $*
    sleep $delay
    ininterval $delay $*
}

или добавьте:

ininterval $*

и назовите сценарий.

0
27.01.2020, 19:28

Как упомянуто gbrandt, если watch команда доступна, определенно используйте ее. Некоторым системам Unix, однако, не установили его по умолчанию (по крайней мере, они не делают, где я работаю).

Вот другое решение с немного отличающимся синтаксисом и выводом (работы в Bash и SH):

while [ 1 ] ; do
    <cmd>
    sleep <x>
    echo ">>>>>>>>>>>>>" `date` ">>>>>>>>>>>>>>"
done

Править: Я удалил некоторых "." в последнем операторе эха... пережиток с моих дней Perl ;)

3
27.01.2020, 19:28
  • 1
    while [ 1 ] только работы, потому что 1 рассматривается как строку, точно так же, как while [ -n 1 ]. while [ 0 ] или while [ jeff ] сделал бы то же самое. while true имеет намного больше смысла. –  Mikel 05.04.2011, 13:19

Perl

#!/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); 
}
4
27.01.2020, 19:28

Хотеть попробовать это (Bash)?

forever ()   {
    TIMES=shift;
    SLEEP=shift;
    if [ "$TIMES" = "-1" ]; then  
        while true;
        do 
            $@
            sleep $SLEEP
        done
    else
        repeat "$TIMES" $@ 
    fi; }
4
27.01.2020, 19:28
  • 1
    часов, который я не к горячему в оболочке, таким образом, приветствующиеся улучшения. И у меня, кажется, нет "повторной" команды в моем дистрибутиве. –   17.02.2009, 02:40
  • 2
    repeat характерно для csh и tcsh. –  Keith Thompson 12.01.2012, 11:42
  • 3
    @KeithThompson: и zsh –  Thor 02.08.2017, 12:57

В 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}'
17
27.01.2020, 19:28
  • 1
    while [ 0 ] плохой путь состоит в том, чтобы записать это. Это означает 0 строка с длиной> 0. while [ 1 ] или while [ jeff ] сделал бы то же самое. Лучше записать while true. –  Mikel 05.04.2011, 13:17
  • 2
    @Mikel: Или while : –  Keith Thompson 12.01.2012, 11:27

Bash

while + sleep:

while true
do 
    echo "Hi"
    sleep 1
done

Вот то же самое как краткая острота (Из комментариев ниже):

while sleep 1; do echo "Hi"; done

Использование ; разделить команды и использование sleep 1 для while тест, так как это всегда возвращает true. Можно поместить больше команд в цикл - просто разделяют их с ;

252
27.01.2020, 19:28
  • 1
    я верю этому, работает, как записано в универсальной Оболочке Bourne, также. –  dmckee --- ex-moderator kitten 17.02.2009, 02:24
  • 2
    @dreeves, использование""; как разделитель, команды могут быть execeted в одной строке. Взгляд на ответ Toony как пример –  bbaja42 12.01.2012, 11:00
  • 3
    1 всегда возвращает true, таким образом, можно использовать его в качестве в то время как условие. Не самая читаемая вещь в мире, но абсолютно законный: в то время как сон 1; действительно отзовитесь эхом "Привет"; сделанный –  David Costa 12.01.2012, 12:46
  • 4
    @David Costa: Вы высказали разумное мнение, но sleep не всегда возвращает true. Ī ̲ использовал такие циклы (хотя с более длинной задержкой) а именно, потому что существует способ завершить его корректно с уничтожением спящего процесса. –  Incnis Mrsi 13.09.2015, 01:53
  • 5
    @IncnisMrsi я не думал о нем, он на самом деле, возвращает нуль только, когда время передало и ненулевой, когда это завершается сигналом. Спасибо за указание на него –  David Costa 13.09.2015, 12:58

Это решение работает в 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'

очищать мой рабочий стол постоянно.

0
27.01.2020, 19:28
  • 1
    Сделал Вы означаете иметь a sleep управлять там? –  Keith Thompson 12.01.2012, 11:41
  • 2
    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 является правильным?

1
27.01.2020, 19:28
  • 1
    !? Зачем? sleep $1; shift; "$@" или подобный было бы намного лучше. –  Mikel 20.04.2012, 05:01
  • 2
    Не знайте, почему это-2. оценка может быть излишеством... кроме тех случаев, когда Вам нужен он. Оценка позволяет Вам получить вещи как перенаправление на командную строку. –  Johan 15.03.2013, 11:07

Если Ваше намерение не состоит в том, чтобы отобразить сообщение на Ваш экран, и если бы Вы могли бы позволить себе повторить, что задание с точки зрения минут, crontab, возможно, было бы Вашим лучшим инструментом. Например, если бы Вы хотите выполнить свою команду каждую минуту, Вы записали бы что-то вроде этого в Вашем crontab файл:

* * * * * my_precious_command

Проверьте учебное руководство для дальнейшего примера. Кроме того, можно установить синхронизации легко с помощью Генератора кода Crontab.

4
27.01.2020, 19:28

Одна проблема, которую до сих пор, имеют все ответы, отправленные, состоит в том, что время, команда выполняется, может дрейфовать. Например, если Вы делаете 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?)
}
46
27.01.2020, 19:28
  • 1
  • 2
    , более простой в ударе минимизировать дрейф (хотя это может дрейфовать по очень длинным окнам использования из-за команды сна и самого удара, накапливающего его крошечное время выполнения): while :; do sleep 1m & command; wait; done –  math 14.09.2017, 16:53
  • 3
    @math: Умный. Это не работает, если у Вас есть другие фоновые процессы, работающие в текущей оболочке (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

и это - все!

Приятного отдыха!

-1
27.01.2020, 19:28
  • 1
    Это не корректно. */60 собирается работать каждые 60 минут, и */5, например, каждые 5 минут. –  mika 02.10.2013, 20:47
  • 2
    не позволяются на crontab –  GAD3R 30.11.2017, 14:12

Для повторного выполнения команды в консоли, я обычно выполняю что-то вроде этого:

while true; do (run command here); done

Это работает на несколько команд также, например, для отображения постоянно обновляющих часов в консоли:

while true; do clear; date; sleep 1; done

0
27.01.2020, 19:28
  • 1
    Почему downvote? Вы видите, что это - рабочее решение копией и вставкой примера в окно терминала. –  Thomas Bratt 27.01.2013, 16:20
  • 2
    я думаю, что Вы спустились проголосовавшие, потому что это немного опасно и использует ЦП. –  ojblass 06.07.2013, 23:22

Это - просто более короткая версия другого while+sleep ответы при выполнении этого вида задач часто как распорядок дня, с помощью этого, сохраняют Вас от ненужных нажатий клавиш, и если Ваша командная строка начинает получать более долгое понимание, что этот немного легче. Но этот запускает со сна сначала.

Это обычно полезно, если необходимо следовать, что-то имеет короткий вывод как загрузка машины:

while sleep 1; do uptime; done
74
27.01.2020, 19:28
  • 1
    Да. Это должно быть зарегистрировано рядом с UUOC. –  Johan 15.03.2013, 11:05
  • 2
    И если Вы хотите, чтобы это работало как "часы", можно сделать while clear; do date; command;sleep 5; done –  Johan 15.03.2013, 11:12
  • 3
    Ничего себе, спасибо за while sleep комбинация, сохраняет keystokes! –  George Y. 05.06.2016, 05:34

Bash и некоторые его родственные оболочки имеет удобное (( ... )) нотация, где арифметические выражения могут быть оценены.

Таким образом, поскольку ответ на Ваш третий вызов, где оба повторный счет и задержка между каждым повторением должны настраиваться, вот является одним способом сделать это:

repeat=10
delay=1

i=0
while (( i++ < repeat )); do
  echo Repetition $i
  sleep $delay
done

Этот ответ также страдает от дрейфа синхронизации, охваченного в ответе Keith.

4
27.01.2020, 19:28

Вы могли запустить скрипт от init (добавляющий строку к/etc/inittab). Этот сценарий должен выполнить Вашу команду, сон в течение времени, Вы хотите ожидать, пока не запущено скрипт снова и выйти из него. Init запустит Ваш сценарий снова после выхода.

1
27.01.2020, 19:28

Что, если у нас были оба?

Вот идея: только с "интервалом" это повторяется навсегда. С "интервалом" и "времена", это повторяет это количество раз, разделенное "интервалом".

Использование:

$ loop [interval [times]] command

Так, алгоритм будет:

  • Элемент списка
  • если 1$ содержит только цифры, это - интервал (значение по умолчанию 2)
  • если 2$ содержат только цифры, это - количество раз (большое количество по умолчанию)
  • цикл с условием продолжения с этими параметрами
    • сон "интервал"
    • если неоднократно был дан, постепенно уменьшите var, пока он не достигнут

Поэтому:

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
}
3
27.01.2020, 19:28
  • 1
    Отметьте: это не работает с плаваниями, несмотря на 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
0
27.01.2020, 19:28

Недавний удар> = 4.2 под недавним ядром Linux, базирующимся ответом.

Для ограничения времени выполнения нет никаких ветвлений! Только встроенный используются.

Для этого я использую 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
10
27.01.2020, 19:28
  • 1
    read -t встроенное, в то время как sleep не. Это могло иметь краевой эффект (т.е. совершающий нападки [key:return] прерывают бесшумно сон), но это можно было рассматривать путем тестирования $foo –  F. Hauri 29.01.2014, 19:34
  • 2
    Очень впечатляющий –  gena2x 04.06.2014, 16:37

Я думаю, что весь ответ здесь до сих пор является или слишком замысловатым, или вместо этого отвечает на другой вопрос:

  • "Как неоднократно запускать программу так, чтобы была задержка X секунд между когда программа, законченная и следующие запуски".

Реальный вопрос был:

  • "Как запускать программу каждые X секунды"

Это две совсем других вещи, когда команда занимает время для окончания.

Возьмите, например, сценарий 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, или что имеет Вас.

32
27.01.2020, 19:28
  • 1
    Те, кто голосовал по различным ответам, не понимайте элегантность своего ответа... –  Serge Stroobandt 27.06.2015, 01:58
  • 2
    Это хорошо, если Ваша программа не имеет побочные эффекты. Если программа занимает больше времени, чем интервал, побочные эффекты могут вмешаться (как перезапись файла). Если программа ожидает чего-то еще, и что что-то еще берет навсегда, то Вы запускаете все больше фоновых заданий неограниченно долго. Используйте с осторожностью. –  John Moeller 16.07.2015, 23:36
  • 3
    мог инвертировать порядок фоновой обработки гарантировать, что не больше чем один./foo.sh выполняется за один раз, но не быстрее, чем 1 в секунду: while :; do sleep 1 & ./foo.sh; wait; done –  math 14.09.2017, 16:57
[116277] Легкий способ повторить задание из кронтаба с интервалом менее одной минуты (пример 20 секунд) :

кронтаб: * * * script.sh

script.sh:

1
27.01.2020, 19:28

Я завел, создавая вариант на ответе Swalog. С его вы должны были подождать x секунды для первой итерации, я также бегаю на переднем плане, так что ...

./foo.sh;while sleep 1; do (./foo.sh) ; done
2
27.01.2020, 19:28
until ! sleep 60; do echo $(date); command; command; command; done

у меня работает.

  1. Мне это не нужно ровно каждые 60 секунд
  2. «часы» не следят за командами во всех системах
  3. «часы» могут принимать только одну команду (или файл сценария)
  4. переводить в спящий режим условие вместо тела делает цикл более прерываемым (так что утверждение в ответе на аналогичный вопрос о stackoverflow. к сожалению, я могу его найти в данный момент)
  5. Я хочу выполнить его один раз перед задержкой, поэтому я использую до тех пор, пока вместо while
-1
27.01.2020, 19:28

Вы можете получить мощность от интерпретатора Python из оболочки.

python3 -c "import time, os
while True:
    os.system('your command')
    time.sleep(5)

заменить пять в любое время (сек )вы хотите.

Внимание :при возврате используйте SHIFT+ENTER для возврата ввода в оболочку. И не забудьте набрать 4 ПРОБЕЛ отступ в каждой строке в цикле while.

2
27.01.2020, 19:28

С zshи реализацией sleep, которая принимает аргументы с плавающей запятой -:

typeset -F SECONDS=0 n=0
repeat 100 {cmd; sleep $(((n+=3) - SECONDS))}

Или дляforever:

for ((;;)) {cmd; sleep $(((n+=3) - SECONDS))}

Если ваш sleepне поддерживает числа с плавающей запятой, вы всегда можете переопределить его как оболочку вокруг встроенной функции zshzselect:

zmodload zsh/zselect
sleep() zselect -t $((($1 * 100) | 0))
0
27.01.2020, 19:28

Теги

Похожие вопросы