Повторите команду каждый x интервал времени в терминале?

143

Как я могу повторять команду каждый интервал времени, чтобы она позволяла мне запускать команды для проверки или мониторинга каталогов?

Нет необходимости в скрипте, мне нужно просто выполнить простую команду в терминале.

Мур
источник

Ответы:

220

Вы можете использовать watchкоманду, часы используются для запуска любой назначенной команды через равные промежутки времени.

Откройте Терминал и введите:

watch -n x <your command>

замените x на желаемое время в секундах.

Для получения дополнительной помощи, используя watchкоманду и ее параметры, запустите man watchили перейдите по этой ссылке .

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

watch -n 60 ls -l ~/Desktop
Nux
источник
34
+1, но будьте осторожны при использовании расширений. Например, попробуйте разницу между watch -n 1 'echo $COLUMNS'и watch -n 1 echo $COLUMNSпри изменении размера вашего терминала - первый расширяется каждую секунду, но последний расширяется только один раз перед watch запуском.
10
Отлично работает ! Ty nux
Проблема, с которой я столкнулся в этом решении, заключается в том, что вы не можете запустить watch как процесс и просто оставить его запущенным в фоновом режиме (например, с & disown)
Cestarian
2
Есть ли способ использовать watchс командой типа «история включена»? Я люблю использовать watch, но иногда я предпочитаю видеть журнал предыдущих выполнений, а не только последнее. И да, я знаю, что для этого могу использовать scripting ( while true), но использование watchутилиты намного чище!
Риного
это работало для более простых команд, но с конвейерными командами цепочки это не работало для меня .. следующая команда была, которую я попробовал => cat api.log | grep 'Calling' | 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.

В вышеуказанных обстоятельствах это может показаться лучшим вариантом.

souravc
источник
watchсуществует для этого, это немного бесполезно, я бы сказал
Бруно Перейра
14
Я не утверждаю, что этот ответ должен использоваться в первую очередь. watchэто хорошо в большинстве случаев. Вот почему я упомянул «помимо ответа nux» в начале. Но есть несколько проблем, watchнапример. Один не может использовать какие-либо команды с псевдонимамиwatch . Возьмем, к примеру, llпсевдоним, который ls -laFнельзя использовать с watch. Также в случае, если вывод какой-либо команды достаточно длинный, у вас будут проблемы с прокруткой watch. В этих нескольких особых случаях этот ответ может оказаться лучшим вариантом.
souravc
@souravc Моя версия, watchпо крайней мере, позволяет использовать опции -cили --colorдля цветного вывода.
Лили Чунг
8
while sleep xлучше - легче убить
d33tah
3
Это хорошая альтернатива и, в отличие от watchнее, она хранит историю команд.
adelriosantiago
34

Просто хотел ответить на вопросы от suravc и nux :

  1. Хотя он watchбудет отлично работать в Ubuntu, вы можете избежать этого, если хотите, чтобы ваш «Unix-fu» был чистым - например, во FreeBSD, watch - это команда, «отслеживающая другую строку tty».
  2. while true; do command; sleep SECONDS; doneтакже есть один нюанс - ваша команда может быть труднее убить с помощью CTR + C . Вы можете предпочесть while sleep SECONDS; do command; done- это не только короче, но и легче прерывать. Предостережение заключается в том, что сначала он будет переведен в спящий режим, а затем запустит вашу команду, поэтому вам придется подождать некоторое время, SECONDSпрежде чем произойдет первое появление команды.
d33tah
источник
2
Надеюсь, что это приемлемо в качестве ответа вместо комментария - я хотел показать здесь другое решение, а комментирование фактически дало бы мне меньше внимания.
d33tah
Почему именно это важно, где вы положили sleepв whileпетле? Я не мог найти никакой разницы, Ctrl + C сломал петлю сразу ни на что.
десерт
@ Dessert: зависит от того, что вы пытаетесь вырваться из, я думаю. Обычно, Ctrl + C просто убил бы вас commandи sleepсломался, только если вы убили true.
d33tah
11

Похоже, идеальная задача для cronдемона, который позволяет выполнять периодические команды. Запустите crontab -eкоманду, чтобы начать редактирование конфигурации cron вашего пользователя. Его формат задокументирован в 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"
Lekensteyn
источник
4
Вопрос в том, как периодически что-то запускать в терминале. cronработает за кулисами, а не в терминале
Northern-Bradley
5

Если вы наблюдаете за файловой системой, inotifywaitэто замечательно и, безусловно, добавляет меньше нагрузки на вашу систему.

Пример :

В 1-м терминале введите эту команду:

$ 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.
X Тянь
источник
пользователь сказал вам, нет сценария, и, возможно, он не хочет ничего контролировать
nux
3
Я не велел ему писать сценарии, я предложил, что если они зацикливаются на порядке следования за определенным событием файловой системы, тогда inotifywait полезен и использует меньше ресурсов, чем повторение команды. Я часто запускаю несколько команд в командной строке, например grep something InALogFile|less, это скрипт?
X Tian
Это хороший ответ, попробуйте отредактировать его, чтобы он выглядел более простым.
Nux
3
Что может быть проще, чем .я не могу пропустить команду.
X Tian
Спасибо @XTian, ​​отличная команда. Я также теперь видел на странице руководства, которую вы можете добавить -mдля постоянного мониторинга без петель.
yoniLavi
4

Вы можете создать свою собственную repeatкоманду, выполнив следующие шаги; кредиты здесь :

Сначала откройте ваш .bash_aliasesфайл:

$ xdg-open ~/.bash-aliases

Затем вставьте эти строки внизу файла и сохраните:

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

В-третьих, либо закройте и снова откройте свой терминал, либо введите:

$ source ~/.bash_aliases

И вуаля ! Теперь вы можете использовать его так:

$ repeat 5 echo Hello World !!!

или же

$ repeat 5 ./myscript.sh
Blufter
источник
в строке xdg-open ~ / .bash-aliases есть небольшая опечатка. это должно быть: xdg-open ~ / .bash_aliases (то есть: подчеркивание)
ssinfod
4

Вы можете использовать crontab. запустите команду 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

Х количество раз повторить.

У времени ждать, чтобы повторить.

Пример :

$ echo; for i in $(seq 5); do $cmd "This is echo number: $i"; sleep 1;done
Maythux
источник
Почему это улучшение? Вы только что добавили дополнительный, ненужный шаг, сохранив команду как переменную. Единственное , что это делает я) сделать больше , чтобы тип II) заставляет вас использовать только простые команды, ни труб или переадресовывает и т.д.
terdon
Удалите лишнюю переменную
Maythux
3

Другая проблема, связанная с подходом «наблюдения», предложенным выше, заключается в том, что он отображает результат только после завершения процесса. «date; sleep 58; date» отобразит 2 даты только через 59 секунд ... Если вы запустите что-то, работающее в течение 4 минут, которое медленно отображает несколько страниц контента, вы на самом деле не увидите его.

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

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

При этом скрипт будет запускаться где-то каждую минуту, иногда это может занять 1 мин 40. Таким образом, даже если cron сможет запускать его каждую минуту, здесь это не так.

Таким образом, чтобы увидеть вывод на оболочке в том виде, как она сгенерирована, и ждать точного времени запроса, вам нужно посмотреть на время до и после, и выполнить цикл с while.

Что-то вроде:

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

Так что просто замените команду «sleep 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
jmspaggi
источник
Отвечая самому себе ... Если ваша команда занимает больше, чем настроенная вами задержка, $ DELAY получит отрицательное значение, а команда sleep завершится ошибкой, поэтому скрипт сразу же перезапустится. Нужно знать об этом.
jmspaggi