Виконуйте команду кожні X секунд


10

Я хочу виконати команду будь-коли 10 секунд, і виконати її у фоновому режимі (тим самим усунути watch?). Усі відповіді показують щось на зразок наступного, але це триватиме 11–14 секунд. Як це можна досягти?

while true; do
    # perform command that takes between 1 and 4 seconds
    sleep 10
done

можливо, з сигналами в реальному часі. та правильне поводження з високосними секундами. Щасти.
mikeserv

@mikeserv Отже, не турбуйтеся намагатися? Мене не хвилює точність мілілінд, просто скажіть півсекунди.
користувач1032531

Що ви намагаєтеся досягти? Я вважаю, що завдання, яке доводиться виконувати з такою частотою, зазвичай є вирішенням іншої проблеми.
Sobrique

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

Відповіді:


16

Як щодо:

( # In a subshell, for isolation, protecting $!
  while true; do
    perform-command & # in the background
    sleep 10 ;
    ### If you want to wait for a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line:
    # wait $! ;
    ### If you prefer to kill a perform-command
    ### that happens to run for more than ten seconds,
    ### uncomment the following line instead:
    # kill $! ;
    ### (If you prefer to ignore it, uncomment neither.)
  done
)

ETA: З усіма цими коментарями, альтернативами та додатковою оболонкою для додаткового захисту це виглядає набагато складніше, ніж це було розпочато. Отже, для порівняння, ось як це виглядало до того, як я почав хвилюватися waitабо kill, з їхньою $!потребою та ізоляцією:

while true; do perform-command & sleep 10 ; done

Решта справді лише для того, коли вам це потрібно.


Чи можете ви пояснити міркування, що стоять за вашим дамп-кодом?
Ісмаїл Мігель

2
Також цитувати, на яку оболонку працює ваш код (на зразок відповіді mikeserv), щоб люди не плуталися, коли інша оболонка поводиться інакше :)
попел

@IsmaelMiguel Я вважав, що коментарі пояснюють міркування. Я не впевнений, що незрозуміло.
Сідекін

1
У посібнику з bash йдеться про $!: "Розширюється на ідентифікатор процесу, який останнім часом розміщується на задньому плані", і цей sleepфайл не розміщується на задньому плані, так що ні, він не буде. :)
Сидекін

1
Ого. не в обох випадках. коли це сталося?
mikeserv

9

Ви можете зробити що - щось подібне до наступного в bash, zshабо ksh:

SECONDS=0
while   command
do      sleep "$((10-(SECONDS%10)))"
done

Ось що bashговорить посібник про $SECONDS:

$SECONDS

  • Щоразу при посиланні на цей параметр повертається кількість секунд після виклику оболонки. Якщо присвоєно значення $SECONDS, значення, яке повертається після наступних посилань, - це кількість секунд з моменту присвоєння плюс присвоєне значення. Якщо $SECONDSце так unset, він втрачає свої особливі властивості, навіть якщо згодом його скидає.

Ось робочий приклад:

(   SECONDS=0
    while   sleep   "$((RANDOM%10))"
    do      sleep   "$((10-(SECONDS%10)))"
            echo    "$SECONDS"
    done
)

10
20
30
40
50
60
70
80
90
100

2
Щоб уникнути перезавантаження, SECONDSробіть sleep "$((10-(($SECONDS-$start_time)%10)))". Вам доведеться зробити start_time=$SECONDSперед циклом.
ctrl-alt-delor

@richard - чому цього уникати?
mikeserv

тому що одного разу ви матимете його у сценарії, до якого ви дзвоните з такої петлі. І ти цілий день будеш дивуватися, чому це не працює належним чином. Коротше кажучи, воно не гніздиться, якщо ви скидаєтесь SECONDS. Нерест підкольори, як і в останньому редагуванні, також повинен уникати цієї проблеми.
ctrl-alt-delor

1
@richard - оскільки питання стосувалося while trueциклу, я не зрозумів, що очікується, що будь-який стан оболонки переживе його. У будь-якому випадку, як правило, найкраща практика - це перетворювати цикл у власному контексті. У такій ситуації я хотів би більше турбуватися про це trapзаради, ніж $SECONDSзаради.
mikeserv

Спасибі Майку, я думав зробити щось подібне (але ще не знав конкретики як). Але рішення Сідекіна, здається, робить те саме, ні? Я не кваліфікований, щоб судити про кращу відповідь, але відчував себе зобов'язаним щось вибрати.
користувач1032531

3

Тільки BASH - Ви також можете обчислити час, витрачений на вашу команду, і відняти 10:

TIMEFORMAT=$'%0R'
while true; do
    T=$({ time command; } 2>&1)
    sleep $(( 10-T ))

Від BASH людина:

TIMEFORMAT Значення цього параметра використовується у вигляді рядка формату, який визначає, як повинна відображатися інформація про терміни для трубопроводів з префіксом зарезервованого за часом слова. Символ% вводить послідовність відходу, яка розширюється на значення часу або іншу інформацію. Послідовності втечі та їх значення наступні; дужки позначають необов'язкові частини.
%% A буквально%.
% [p] [l] R Пройдений час у секундах.
% [p] [l] U Кількість секунд процесора, проведених у режимі користувача.
% [p] [l] S Кількість секунд процесора, проведених у системному режимі.
% P Процент процесора, обчислюється як (% U +% S) /% R.

Необов'язковий p - це цифра, що вказує точність, кількість дробових цифр після десяткових знаків. Значення 0 призводить до виведення жодної десяткової крапки або дробу.

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