Как заставить скрипт unix запускаться каждые 15 секунд?
Я видел несколько решений, в том числе смотреть и просто запустить цикл (и спать) сценарий в фоновом режиме, но ничего не было идеальным.
У меня есть скрипт, который должен запускаться каждые 15 секунд, и поскольку cron не поддерживает секунды, мне остается выяснить что-то еще.
каков самый надежный и эффективный способ запуска скрипта каждые 15 секунд в unix? Скрипт также должен запускаться после перезагрузки.
9 ответов:
Я бы использовал cron для запуска скрипта каждую минуту и заставил этот скрипт запускать ваш скрипт четыре раза с 15-секундным сном между запусками.
(это предполагает, что ваш скрипт быстро запускается - вы можете настроить время сна, если нет.)
таким образом, вы получаете все преимущества
cron
а также 15-секундный период.Edit: см. также комментарий @bmb ниже.
Если вы настаиваете на запуске скрипта из cron:
* * * * * /foo/bar/your_script * * * * * sleep 15; /foo/bar/your_script * * * * * sleep 30; /foo/bar/your_script * * * * * sleep 45; /foo/bar/your_script
и заменить свое имя сценария и путь к /Foo/бар/сценарий
измененная версия выше:
mkdir /etc/cron.15sec mkdir /etc/cron.minute mkdir /etc/cron.5minute
добавить в /etc / crontab:
* * * * * root run-parts /etc/cron.15sec > /dev/null 2> /dev/null * * * * * root sleep 15; run-parts /etc/cron.15sec > /dev/null 2> /dev/null * * * * * root sleep 30; run-parts /etc/cron.15sec > /dev/null 2> /dev/null * * * * * root sleep 45; run-parts /etc/cron.15sec > /dev/null 2> /dev/null * * * * * root run-parts /etc/cron.minute > /dev/null 2> /dev/null */5 * * * * root run-parts /etc/cron.5minute > /dev/null 2> /dev/null
не будет ли это работать в фоновом режиме?
#!/bin/sh while [ 1 ]; do echo "Hell yeah!" & sleep 15 done
Это примерно так же эффективно, как это добирается. Важная часть выполняется только каждые 15 секунд, а сценарий спит остальное время (таким образом, не тратя циклы).
Я написал планировщик быстрее, чем cron. Я также реализовал перекрывающийся охранник. Вы можете настроить планировщик, чтобы не запускать новый процесс, если предыдущий все еще работает. Взгляните на https://github.com/sioux1977/scheduler/wiki
использовать nanosleep(2). Он использует структуру
timespec
используется для указания интервалов времени с точностью до наносекунды.struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ };
#! /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 [ = cronsec ] then 2 & 3 & 4 & 5 & 6 & 10 & 12 & 15 & 20 & 30 & exit fi # Set the directory to first prameter and delay to second parameter dir= delay= # 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 [[ "" =~ ^(2|3|4|5|6|10|12|15|20|30)$ ]] then dir="/etc/cron.sec" delay= 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 . $dir $delay & fi # Otherwise we're done
С момента моего предыдущего ответа я придумал другое решение, которое отличается и, возможно, лучше. Этот код позволяет запускать процессы более 60 раз в минуту с точностью до микросекунды. Вам нужна программа usleep, чтобы сделать эту работу. Должны быть хорошо до 50 раз в секунду.
#! /bin/sh # Microsecond Cron # Usage: cron-ms start # Copyright 2014 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 basedir=/etc/cron-ms if [ $# -eq 0 ] then echo echo "cron-ms by Marc Perkel" echo echo "This program is used to run all programs in a directory in parallel every X times per minute." echo "Think of this program as cron with microseconds resolution." echo echo "Usage: cron-ms start" echo echo "The scheduling is done by creating directories with the number of" echo "executions per minute as part of the directory name." echo echo "Examples:" echo " /etc/cron-ms/7 # Executes everything in that directory 7 times a minute" echo " /etc/cron-ms/30 # Executes everything in that directory 30 times a minute" echo " /etc/cron-ms/600 # Executes everything in that directory 10 times a second" echo " /etc/cron-ms/2400 # Executes everything in that directory 40 times a second" echo exit fi # If "start" is passed as a parameter then run all the loops in parallel # The number of the directory is the number of executions per minute # Since cron isn't accurate we need to start at top of next minute if [ = start ] then for dir in $basedir/* ; do ${dir##*/} 60000000 & done exit fi # Loops per minute and the next interval are passed on the command line with each loop loops= next_interval= # Sleeps until a specific part of a minute with microsecond resolution. 60000000 is full minute usleep $(( $next_interval - 10#$(date +%S%N) / 1000 )) # Run all the programs in the directory in parallel for program in $basedir/$loops/* ; do if [ -x $program ] then $program &> /dev/null & fi done # Calculate next_interval next_interval=$(($next_interval % 60000000 + (60000000 / $loops) )) # If minute is not up - call self recursively if [ $next_interval -lt $(( 60000000 / $loops * $loops)) ] then . $loops $next_interval & fi # Otherwise we're done
чтобы избежать возможного перекрытия исполнения, используйте механизм блокировки, как описано в этом thread.