如何获得一个UNIX脚本每15秒运行一次?

我已经看到了一些解决scheme,包括监视和简单地在后台运行循环(和睡眠)脚本,但没有什么是理想的。

我有一个需要每15秒运行一次的脚本,由于cron不会支持秒,所以我只能找出其他的东西。

什么是在UNIX上每15秒运行脚本的最健壮和最有效的方法? 该脚本还需要在重新启动后运行。

我会每隔一分钟使用cron来运行一个脚本,然后让这个脚本在运行之间以15秒的时间间隔运行脚本四次。

(假设你的脚本很快运行 – 如果没有,你可以调整睡眠时间。)

这样,你就可以获得cron所有好处以及15秒的运行时间。

编辑:请参阅下面的@ bmb的评论。

如果你坚持从cron运行你的脚本:

 * * * * * /foo/bar/your_script * * * * * sleep 15; /foo/bar/your_script * * * * * sleep 30; /foo/bar/your_script * * * * * sleep 45; /foo/bar/your_script 

并将您的脚本名称和pathreplace为/ foo / bar / your_script

以上修改版本:

 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秒执行一次,脚本会hibernate(因此不会浪费周期)。

我比cron写了一个调度器。 我也执行了一个重叠的后卫。 如果前一个仍在运行,您可以configuration调度程序不启动新的进程。 看看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 [ $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 

自从我以前的答案,我想出了另一个不同的,也许更好的解决scheme。 这个代码允许进程每分钟运行超过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 [ $1 = start ] then for dir in $basedir/* ; do $0 ${dir##*/} 60000000 & done exit fi # Loops per minute and the next interval are passed on the command line with each loop loops=$1 next_interval=$2 # 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 . $0 $loops $next_interval & fi # Otherwise we're done 

为了避免可能的执行重叠,请使用该线程中描述的locking机制。