Повторюйте команду Unix кожні x секунд назавжди


480

Існує вбудована команда Unix repeat, першим аргументом якої є кількість разів повторення команди, де команда (з будь-якими аргументами) задається рештою аргументів repeat.

Наприклад,

% repeat 100 echo "I will not automate this punishment."

повторюватиметься даним рядком 100 разів, а потім зупиняється.

Я хотів би подібна команда - назвемо її forever- яка працює аналогічно, за винятком першого аргументу - це кількість секунд, щоб зробити паузу між повторами, і вона повторюється назавжди. Наприклад,

% forever 5 echo "This will get echoed every 5 seconds forever and ever."

Я думав, що запитаю, чи існує така річ, перш ніж я її напишу. Я знаю, що це як дворядковий сценарій Perl або Python, але, можливо, є більш стандартний спосіб зробити це. Якщо ні, сміливо публікуйте рішення улюбленою мовою сценаріїв, стилем Rosetta Stone .

PS: Можливо, кращим способом зробити це було б узагальнення, repeatщоб взяти як кількість повторень (з значенням -1 означає нескінченність), так і кількість секунд, щоб проспати між повторами. Наведені вище приклади стануть:

% repeat 100 0 echo "I will not automate this punishment."
% repeat -1 5 echo "This will get echoed every 5 seconds forever."

1
Чому б не: повторити команду [-t time] [-n number] [args ...]?
Джонатан Леффлер

17
Класно. На жаль , як на моєму Ubuntu і мій AIX повторити це команда не знайдено . Чи можете ви зробити це, type repeatі дайте мені знати, звідки беруться?

3
Я також на Ubuntu і не маю повторень. Будь-яка інформація про те, як встановити це, була б корисною.
Рорі

7
repeat- це вбудована команда в csh та tcsh.
Кіт Томпсон

2
@KeithThompson, csh, tcsh та zsh . Хоча це більше ключове слово, ніж вбудований
Stéphane Chazelas

Відповіді:


615

Спробуйте 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

Або ви можете отримати його від Homebrew :

brew install watch

2
ви можете використовувати MacPorts для його встановлення. sudo port install watch

10
Також доступний на домашній мові (brew install watch).
Лайл

28
+1 Для нового потужного інструменту. Я звик while true; do X; sleep Y; done- Це краще.
Адам Матан

4
Проблема з цим інструментом (принаймні на Ubuntu) полягає в тому, що він примушує повноекранний екран, тому якщо я скидаю деяку періодичну інформацію, я втрачаю попередню інформацію.
скорпіодавг

4
Він викликається cmdwatchу FreeBSD (з портів:) sysutils/cmdwatch.
Ouki

243

Баш

while+ sleep:

while true
do 
    echo "Hi"
    sleep 1
done

Ось те ж саме, що і скорочений однокласник (З коментарів нижче):

while sleep 1; do echo "Hi"; done

Використовується ;для поділу команд і використовує sleep 1для whileтестування , так як він завжди повертає істину. У цикл можна помістити більше команд - просто розділіть їх;


2
Я вважаю, що це працює так, як написано в загальній оболонці Борна.
dmckee

5
@dreeves, використовуючи ";" Як роздільник команди можна виконувати в одному рядку. Подивіться на приклад відповіді
Тоні

56
сон 1 завжди повертається істинно, тому ви можете використовувати його як стан. Не найчитабельніша річ у світі, але абсолютно законна: під час сну 1; робити відлуння "Привіт"; готово
Девід Коста

3
@David Costa: Ви зробили розумну точку, але sleepне завжди повертаєте правду. Ī̲ використовували такі петлі (хоча і з більш тривалою затримкою), а саме тому, що існує спосіб витончено його припинити, вбиваючи процес сну.
Incnis Mrsi

2
@IncnisMrsi Я не думав про це, він фактично повертає нуль лише тоді, коли минув час, і ненульовий, коли він закінчується сигналом. Дякуємо, що вказали на це
Девід Коста,

71

Це лише більш коротка версія інших while+sleepвідповідей, якщо ви виконуєте подібні завдання часто як розпорядок дня, використання цього позбавляє вас від зайвих натискань клавіш, і якщо ваш командний рядок починає довше розуміти, це трохи легше. Але цей починається спочатку спати.

Це, як правило, корисно, якщо вам потрібно дотримуватися того, що щось має однорядний вихід, як завантаження машини:

while sleep 1; do uptime; done

Так. Це має бути задокументовано поруч із УУПЦ.
Йохан

10
І якщо ви хочете, щоб він працював як "дивитися", ви можете це зробитиwhile clear; do date; command;sleep 5; done
Йохан

Нічого, дякую за while sleepкомбінацію, економить клавіші!
Джордж Ю.

45

Однією з проблем, на яку всі відповіді, розміщені до цих пір, є те, що час виконання команди може переміститися. Наприклад, якщо ви робите sleep 10між командами, а команда займає 2 секунди для запуску, то вона запускається кожні 12 секунд; якщо для запуску потрібен мінливий проміжок часу, то в довгостроковій перспективі час, коли він працює, може бути непередбачуваним.

Це може бути саме те, що ви хочете; якщо так, використовуйте одне з інших рішень або використовуйте це, але спрощуйте sleepвиклик.

Для однохвилинної роздільної здатності завдання cron виконуватимуться у визначений час, незалежно від того, скільки часу займає кожна команда. (Насправді нове завдання в галузі Cron запуститься, навіть якщо попереднє все ще працює.)

Ось простий скрипт Perl, який спить до наступного інтервалу, тому, наприклад, з інтервалом 10 секунд команда може виконуватись у 12:34:00, 12:34:10, 12:34:20 тощо, навіть якщо Сама команда займає кілька секунд. Якщо команда працює більше intervalсекунд, наступний інтервал буде пропущений (на відміну від cron). Інтервал обчислюється відносно епохи, тому інтервал 86400 секунд (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?)
}


1
простіший в bash, щоб мінімізувати дрейф (хоча він може переноситись через дуже довгі вікна використання завдяки команді сну і сам баш накопичує свої крихітні часи виконання): while :; do sleep 1m & command; wait; done
математика

1
@math: Розумний. Він не працює, якщо в поточній оболонці запущені інші фонові процеси ( waitбуде чекати всіх). Це можна виправити шляхом зміни waitв wait $!, де $!це PID від sleepпроцесу. Опублікуйте це як відповідь, і я його схвалюю. Але це дає певний вихід у інтерактивній оболонці.
Кіт Томпсон

29

Я думаю, що всі відповіді тут поки занадто суперечливі, або натомість відповідають на інше питання:

  • Msgstr "Як запускати програму кілька разів, щоб було тривалі затримки між 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, або що у вас є.


1
Ті, хто проголосував за різні відповіді, не розуміють елегантності вашої відповіді ...
Серж Стройбандт

Це добре, якщо ваша програма не має побічних ефектів. Якщо програма займає більше інтервалу, побічні ефекти можуть заважати (наприклад, перезапис файлу). Якщо програма чекає чогось іншого, а щось інше бере назавжди, то ви починаєте все більше і більше фонових завдань на невизначений час. Використовуйте обережно.
Джон Моеллер

4
може перевернути порядок фонового зображення, щоб переконатися, що не більше одного ./foo.sh запускається за один раз, але не швидше 1 секунди: while :; do sleep 1 & ./foo.sh; wait; done
математика

Так, вона буде дрейфувати, кілька мілісекунд на кожен цикл, але так і буде. Створіть date +"%H:%M:%S.%N"у foo.sh, щоб побачити, як частка повільно збільшуватиметься на кожній петлі.
Ісаак

Так, це правда, що більшість відповідей буквально не стосуються цього питання. Але це майже безпечна ставка, що вони відповідають, чого хотів ОП. Більш безпечним було б, якби ОП насправді прийняв відповідь ... Але це добре, за умови, що ви знаєте про можливі побічні ефекти і ви впевнені, що середній час виконання команди не перевищить час циклу
Auspex

17

В 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"можна було замінити команду "будь-яку", оточену задньою кнопкою (`).

А для паузи додайте sleepвислів всередині циклу for:

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}'

16
while [ 0 ]це поганий спосіб його написання. Це означає 0, що це рядок довжиною> 0. while [ 1 ]або while [ jeff ]зробив би те саме. Краще писати while true.
Мікель

5
@Mikel: Абоwhile :
Кіт Томпсон

10

Останній bash> = 4.2 під останнім ядром Linux на основі відповіді.

Для того, щоб обмежити час виконання, вил немає ! Використовуються лише вбудовані.

Для цього я використовую readвбудовану функцію замість sleep. На жаль, це не спрацює з непомітними сеансами.

Функція швидкого " 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 існує профайл, /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:

# 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поки ні. Це може мати ефект кордону (тобто натискання [клавіша: повернення] спокійно переривати сон ), але це можна вирішити шляхом тестування$foo
Ф. Хаурі

Дуже вражаюча відповідь
gena2x

4

Хочете спробувати це (Bash)?

forever ()   {
    TIMES=shift;
    SLEEP=shift;
    if [ "$TIMES" = "-1" ]; then  
        while true;
        do 
            $@
            sleep $SLEEP
        done
    else
        repeat "$TIMES" $@ 
    fi; }

Я не гарячу в оболонці, тому поліпшення вітаються. І я, здається, не маю команди «повторити» в своєму дистрофії.

2
repeatхарактерний для csh та tcsh.
Кіт Томпсон

2
@KeithThompson: і zsh
Thor

4

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

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

Отже, як відповідь на ваш третій виклик, коли і кількість повторень, і затримка між кожним повторенням повинні бути налаштовані, ось один із способів зробити це:

repeat=10
delay=1

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

Ця відповідь також страждає від дрейфу часу, який охоплює відповідь Кіта .


Це було найкраще.
Ахмад Авайс

3

Як згадував gbrandt, якщо watchкоманда доступна, обов'язково використовуйте її. Однак деякі системи Unix не встановлюють його за замовчуванням (принаймні, там, де я не працюю).

Ось ще одне рішення з дещо іншим синтаксисом та результатом (працює в BASH та SH):

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

Редагувати: я видалив декілька "". в останньому ехо-заяві ... відмовлення від моїх днів Perl;)


3
while [ 1 ]працює лише тому, що 1 трактується як рядок, так само, як while [ -n 1 ]. while [ 0 ]або while [ jeff ]зробив би те саме. while trueмає набагато більше сенсу.
Мікель

3

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

* * * * * my_precious_command

Будь ласка, ознайомтеся з підручником для подальшого прикладу. Крім того, ви можете легко встановити таймінги за допомогою генератора кодів Crontab .


3

Що робити, якби у нас було обоє?

Ось ідея: маючи лише "інтервал", він повторюється назавжди. З "інтервалом" і "разів" він повторює цю кількість разів, розділену "інтервалом".

Використання:

$ loop [interval [times]] command

Отже, алгоритм буде:

  • Елемент списку
  • якщо $ 1 містить лише цифри, це інтервал (за замовчуванням 2)
  • якщо $ 2 містить лише цифри, це кількість разів (нескінченна безмежна)
  • при цьому цикл з цими параметрами
    • "інтервал" сну
    • якщо дано кілька разів, зменшуйте вар, поки не буде досягнуто

Тому:

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він їх приймає.
Бароноване

2

Я завершив створення варіанту на відповідь свологу. З його вам довелося чекати X секунд на першу ітерацію, я також запускаю свою на передньому плані, так що ..

./foo.sh;while sleep 1; do (./foo.sh) ; done

1

Швидкий, брудний і , можливо , небезпечно для завантаження, але якщо ви заповзятливі й знаєте , що ви робите, покласти це в repeat.shі chmod 755це,

while true
do 
    eval $1 
    sleep $2 
done

Викликайте це с ./repeat.sh <command> <interval>

Моє почуття-павук говорить, що це, мабуть, злий спосіб цього зробити, чи правильно моє почуття-павук?


8
Евал !? Для чого? sleep $1; shift; "$@"чи подібне було б набагато краще.
Мікель

Незнаю чому це -2. eval може бути зайвим ... за винятком випадків, коли це потрібно. Eval дозволяє отримувати такі речі, як перенаправлення в командний рядок.
Йохан

1

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


1

Простий спосіб повторити завдання з crontab з інтервалом менше однієї хвилини (приклад 20 секунд):

crontab: * * * * * script.sh

script.sh:

#!/bin/bash
>>type your commands here.

sleep 20
>>retype your commands here.

sleep 20
>>retype your commands here.

1

Ви можете отримати живлення від інтерпретатора пітона з оболонки.

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

замініть п’ять у будь-який час (сек), який вам подобається.

Увага: повернення використовуйте SHIFT + ENTER для повернення вводу в оболонці. І не забудьте набрати 4 пробіли у кожному рядку у циклі while.


Зверніть увагу , що python«s os.system()запускає оболонку інтерпретувати командний рядок, тому застосування pythonдля запуску снарядів в циклі запустити команду періодично трохи надлишкова. Ви також можете зробити все в оболонці.
Стефан Шазелас

Я погоджуюсь з тобою. Однак існує 5-секундний сон, як ви описали в кожному циклі. Таким чином, додаткові витрати від запуску нової оболонки можна ігнорувати. Якщо ця вартість зробить період довше очікуваного, ви можете скоротити деякий час сну в якості потреби.
pah8J

0

Це рішення працює в 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'

чистити робочий стіл постійно.


1
Ви мали на увазі мати там sleepкоманду?
Кіт Томпсон

4
while [ 0 ]це дивний спосіб написання нескінченного циклу; вона працює, тому що testкоманда (також відома як [) розглядає непусту рядок як істинну. while : ; do ... ; doneє більш ідіоматичним, або, якщо ви хочете, можете використовувати while true ; do ... ; done.
Кіт Томпсон

0

Ви можете джерелом цієї рекурсивної функції:

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

або додати:

ininterval $*

і зателефонуйте за сценарієм.


0

Для повторного запуску команди у вікні консолі я зазвичай виконую щось подібне:

while true; do (run command here); done

Це працює і для кількох команд, наприклад, для відображення годин, що постійно оновлюються, у вікні консолі:

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


Чому потік? Ви можете побачити, що це робоче рішення, скопіювавши і вставши приклад у вікно терміналу.
Томас Братт

Я думаю, що ви проголосували, бо це трохи небезпечно і споживає процесор.
ojblass

0
#! /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

З 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))

-1

... Цікаво, скільки складних рішень можна створити при вирішенні цієї проблеми.

Це може бути так просто ...

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

і ось все!

Насолоджуйтесь!


6
Це неправильно. * / 60 буде працювати кожні 60 хвилин, а * / 5, наприклад, кожні 5 хвилин.
mika

1
секунди заборонено на
кронтабі

перевірити свої речі, перш ніж відповісти неправильним лайном.
sjas

-1
until ! sleep 60; do echo $(date); command; command; command; done

працює для мене.

  1. Мені це не потрібно саме кожні 60 секунд
  2. "watch" не переглядає команди у всіх системах
  3. "Дивитися" може приймати лише одну команду (або файл сценарію)
  4. введення сну в стан замість тіла робить цикл краще переривним (тому заява у відповіді на аналогічне запитання про stackoverflow. На жаль, я можу його знайти зараз)
  5. Я хочу виконати його один раз перед затримкою, тому використовую поки не час

Я щойно помітив, що "до", мабуть, також виконує сон перед першою ітерацією. чи є спосіб поставити умову в кінці циклу в bash?
Тит
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.