Повторити команду кожні х інтервал часу в терміналі?


142

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

Немає потреби в скрипті, мені потрібна просто проста команда, яка повинна виконуватися в терміналі.

Відповіді:


219

Ви можете використовувати watchкоманду, watch використовується для запуску будь-якої призначеної команди через рівні проміжки часу.

Відкрити термінал і ввести:

watch -n x <your command>

зміни x на час, який потрібно в секундах.

Щоб отримати додаткову допомогу щодо використання watchкоманди та її параметрів, запустіть man watchабо відвідайте це Посилання .

Наприклад: нижче буде перераховано кожні 60-ті роки на тому самому Терміналі вміст каталогу Desktop, щоб ви могли знати, чи відбулися якісь зміни:

watch -n 60 ls -l ~/Desktop

34
+1, але будьте обережні, використовуючи розширення. Наприклад, спробуйте різницю між watch -n 1 'echo $COLUMNS'і watch -n 1 echo $COLUMNSпри зміні розміру вашого терміналу - перший розширюється щосекунди, але останній розгортається лише один раз перед watch запуском.
l0b0

Це працює як шарм! Ty nux

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

2
Чи є спосіб використовувати watchкоманду типу "включена історія"? Я люблю використовувати watch, але іноді я вважаю за краще бачити журнал попередніх страт, а не лише останній. І так, я знаю, що я можу використовувати сценарій ( while true), щоб досягти цього, але використання watchутиліти набагато чистіше!
rinogo

це працювало для більш простих команд, але з конвеєрними командами це не працювало для мене. Наступна команда, яку я спробував => cat api.log | греп 'дзвонити' | wc -l
Судіп Бхандарі

90

Ви також можете використовувати цю команду в терміналі, окрім відповіді nux:

while true; do <your_command>; sleep <interval_in_seconds>; done

Приклад

while true; do ls; sleep 2; done

Ця команда буде друкувати вихід з lsінтервалом у 2 секунди.

Використовуйте Ctrl+, Cщоб зупинити процес.

Недоліків мало watch

  • Він не може використовувати будь-які псевдонімні команди.
  • Якщо вихід будь-якої команди досить довгий, прокрутка не працює належним чином.
  • Існує певна проблема встановити максимальний інтервал часу понад певне значення.
  • watchбуде інтерпретувати послідовність кольорів ANSI, передаючи символи втечі, використовуючи -cабо --colorпараметр. Наприклад, вихід pygmentizeбуде працювати, але це не вдасться ls --color=auto.

У вищезазначених обставинах це може виявитися кращим варіантом.


watchіснує для цього, я б трохи марно сказав,
Бруно Перейра

14
Я не претендую на те, що цю відповідь потрібно використовувати спочатку. watchдобре в більшості випадків. Саме тому я на початку згадував "крім відповіді нукса". Але проблем існує, watchнаприклад, наприклад, з ними не можна використовувати жодних псевдонімових командwatch . Візьмемо для прикладу, llякий є псевдонімом, ls -laFале не може бути використаний watch. Також у випадку, якщо вихід будь-якої команди досить довгий, ви будете мати проблеми з прокруткою за допомогою watch. У цих кількох особливих випадках ця відповідь може виявитися кращим варіантом.
souravc

@souravc Моя версія watchпринаймні дозволяє -cабо --colorпараметри для кольорового виводу.
Лілі Чунг

8
while sleep xкраще - вбити легше.
d33tah

3
Це хороша альтернатива і, на відміну від цього watch, вона зберігає історію команд.
adelriosantiago

34

Просто хотів , щоб передати , щоб souravc і Nux відповіді «s:

  1. Хоча watchна Ubuntu ідеально працюватимуть, ви, можливо, захочете уникнути цього, якщо ви хочете, щоб ваш "Unix-fu" був чистим - наприклад, на FreeBSD, watch - це команда "прослуховувати інший рядок".
  2. while true; do command; sleep SECONDS; doneтакож є один нюанс - ваша команда може бути важче вбити з допомогою CTR + C . Можливо, ви хочете віддати перевагу while sleep SECONDS; do command; done- перервати це не тільки коротше, але й простіше. Застереження полягає в тому, що він спочатку спить, потім виконує вашу команду, тому вам доведеться почекати деяких, SECONDSперш ніж відбудеться перше виникнення команди.

2
Сподіваюся, це прийнятно як відповідь, а не коментар - я хотів показати тут інше рішення, і коментування насправді приверне мені менше уваги.
d33tah

Чому саме важливо, куди ви кладете sleepв whileцикл? Я не зміг знайти різниці, Ctrl + C миттєво перервав цикл, незважаючи ні на що.
десерт

@dessert: залежить від того, що ти намагаєшся вирвати з мене, мабуть. Як правило, CTRL + C буде просто вбивати ваш commandі sleepі тільки зламатися , якщо ви вбиваєте true.
d33tah

11

Здається, ідеальне завдання для cronдемона, яке дозволяє виконувати періодичні команди. Виконайте crontab -eкоманду, щоб почати редагувати конфігурацію вашого користувача. Її формат задокументований у crontab (5) . В основному у вас є п'ять пов'язаних з часом, розділених простором полів, за якими слідує команда:

The time and date fields are:

       field          allowed values
       -----          --------------
       minute         0-59
       hour           0-23
       day of month   1-31
       month          1-12 (or names, see below)
       day of week    0-7 (0 or 7 is Sunday, or use names)

Наприклад, якщо ви хочете запустити сценарій Python кожного вівторка, 11:00:

0 11 * * 1 python ~/yourscript.py

Є також деякі спеціальні імена, які замінюють час, наприклад @reboot. Дуже корисно, якщо вам потрібно створити тимчасовий каталог. З мого crontab (з переліком crontab -l):

# Creates a temporary directory for ~/.distcc at boot
@reboot ln -sfn "$(mktemp -d "/tmp/distcc.XXXXXXXX")" "$HOME/.distcc"

4
Питання задає питання, як періодично запускати щось у терміналі. cronбіжить за лаштунками, а не в терміналі
північний Брадлі

5

Якщо ви відстежуєте файлову систему, то inotifywaitце геніально і, безумовно, додає менше навантаження на вашу систему.

Приклад:

У першому терміналі введіть цю команду:

$ inotifywait .

Потім у другому терміналі будь-яка команда, яка впливає на поточний каталог,

$ touch newfile

Тоді в оригінальному терміналі inotifywait прокинеться та повідомить про подію

./ CREATE newfile2

Або в петлі

$ while true ; do inotifywait . ; done
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ DELETE newfile
Setting up watches.  
Watches established.
./ CREATE,ISDIR newdir
Setting up watches.  
Watches established.

Користувач сказав вам, що немає сценарію, і, можливо, він не хоче нічого контролювати
nux

3
Я не сказав йому писати сценарій, я запропонував, що якщо вони зациклюються на замовленні для перегляду конкретної події файлової системи, тоді inotifywait є корисним і використовує менше ресурсів, ніж повторення команди. Я часто запускаю кілька команд у командному рядку, наприклад grep something InALogFile|less, це сценарій?
X Тіан

це гарна відповідь, спробуйте відредагувати його, щоб виглядати простіше.
nux

3
Що може бути простіше, ніж .я не можу залишити команду.
X Тянь

Дякую @XTian, ​​чудова команда. Зараз я також побачив на сторінці man, яку можна додавати -mдо постійного моніторингу без циклу.
yoniLavi

4

Ви можете створити власну repeatкоманду, виконавши наступні дії; кредити тут :

Спочатку відкрийте .bash_aliasesфайл:

$ xdg-open ~/.bash-aliases

По-друге, вставте ці рядки внизу файлу і збережіть:

repeat() {
n=$1
shift
while [ $(( n -= 1 )) -ge 0 ]
do
    "$@"
done
}

По-третє, або закрийте і знову відкрийте свій термінал, або введіть:

$ source ~/.bash_aliases

Et voilà! Тепер ви можете використовувати його так:

$ repeat 5 echo Hello World !!!

або

$ repeat 5 ./myscript.sh

в рядку xdg-open ~ / .bash-псевдоніми є невеликий друкарський помилок. це має бути: xdg-open ~ / .bash_aliases (тобто: підкреслення)
ssinfod

4

можна використовувати кронтаб. запустіть команду crontab -eта відкрийте її у вибраному текстовому редакторі, а потім додайте цей рядок

*/10 * * * *  /path-to-your-command

Це виконуватиме вашу команду кожні 10 хвилин

* */4 * * *  /path-to-your-command

Це виконуватиме вашу команду кожні 4 години

Ще одне можливе рішення

$ ..some command...; for i in $(seq X); do $cmd; sleep Y; done

X кількість разів повторити.

Y час чекати, щоб повторити.

Приклад:

$ echo; for i in $(seq 5); do $cmd "This is echo number: $i"; sleep 1;done

Чому це поліпшення? Ви просто додали додатковий, непотрібний крок, зберігаючи команду як змінну. Єдине, що це робить - це i) зробити це довше вводити ii) змушує вас використовувати лише прості команди, без труб або переадресації тощо
terdon

Видаліть зайву змінну
Maythux

3

Інша проблема, запропонована вище підходом до "дивитися", полягає в тому, що він відображає результат лише тоді, коли процес виконаний. "дата; сон 58; дата" відобразить дві дати лише через 59 секунд ... Якщо ви почнете щось працювати протягом 4 хвилин, яке повільно відображатиме кілька сторінок вмісту, ви його не побачите.

З іншого боку, проблема "під час" викликає занепокоєння тим, що він не враховує тривалість завдання.

while true; do script_that_take_between_10s_to_50s.sh; sleep 50; done

З цим сценарій працюватиме десь кожні хвилини, а інколи це може зайняти 1м40. Тож навіть якщо крон зможе запускати його щохвилини, тут це не буде.

Отже, щоб побачити вихід на оболонці під час його генерування та дочекатися точного часу запиту, вам потрібно переглянути час до, і після, і циклічити з часом.

Щось на зразок:

while ( true ); do
  echo Date starting `date`
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))`
  echo Before waiting `date`
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
  echo Done waiting `date`
done

Це виведе це:

Як бачите, команда виконується кожні хвилини:

Date starting Mon Dec 14 15:49:34 EST 2015
Before waiting Mon Dec 14 15:49:52 EST 2015
Done waiting Mon Dec 14 15:50:34 EST 2015

Date starting Mon Dec 14 15:50:34 EST 2015
Before waiting Mon Dec 14 15:50:39 EST 2015
Done waiting Mon Dec 14 15:51:34 EST 2015

Тому просто замініть команду "сон echo $(( ( RANDOM % 30 ) + 1 ))" на те, що вам завгодно, і що буде виконуватися, на терміналі / оболонці, рівно щохвилини. Якщо ви хочете іншого розкладу, просто змініть "60" секунд на те, що вам потрібно.

Коротша версія без налагоджувальних рядків:

while ( true ); do
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))` # Place you command here
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
done

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