如何让unix脚本每15秒运行一次?

时间:2021-05-29 01:08:43

I've seen a few solutions, including watch and simply running a looping (and sleeping) script in the background, but nothing has been ideal.

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

I have a script that needs to run every 15 seconds, and since cron won't support seconds, I'm left to figuring out something else.

我有一个需要每15秒运行一次的脚本,而且由于cron不会支持秒数,所以我只想搞清楚其他事情。

What's the most robust and efficient way to run a script every 15 seconds on unix? The script needs to also run after a reboot.

在unix上每15秒运行一个脚本最强大,最有效的方法是什么?脚本还需要在重新启动后运行。

9 个解决方案

#1


I would use cron to run a script every minute, and make that script run your script four times with a 15-second sleep between runs.

我会每分钟使用cron运行一个脚本,并使该脚本运行您的脚本四次,运行之间的休眠时间为15秒。

(That assumes your script is quick to run - you could adjust the sleep times if not.)

(这假设您的脚本可以快速运行 - 如果没有,您可以调整睡眠时间。)

That way, you get all the benefits of cron as well as your 15 second run period.

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

Edit: See also @bmb's comment below.

编辑:另见@ bmb的评论如下。

#2


If you insist of running your script from cron:

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

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

and replace your script name&path to /foo/bar/your_script

并将您的脚本名称和路径替换为/ foo / bar / your_script

#3


Modified version of the above:

以上修改版:

mkdir /etc/cron.15sec
mkdir /etc/cron.minute
mkdir /etc/cron.5minute

add to /etc/crontab:

添加到/ 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

#4


Won't running this in the background do it?

不会在后台运行这个吗?

#!/bin/sh
while [ 1 ]; do
    echo "Hell yeah!" &
    sleep 15
done

This is about as efficient as it gets. The important part only gets executed every 15 seconds and the script sleeps the rest of the time (thus not wasting cycles).

这几乎和它一样高效。重要部分仅每15秒执行一次,脚本会在其余时间休眠(因此不会浪费周期)。

#5


I wrote a scheduler faster than cron. I have also implemented an overlapping guard. You can configure the scheduler to not start new process if previous one is still running. Take a look at https://github.com/sioux1977/scheduler/wiki

我写的调度程序比cron更快。我也实施了一个重叠的守卫。您可以将调度程序配置为在前一个进程仍在运行时不启动新进程。看看https://github.com/sioux1977/scheduler/wiki

#6


Use nanosleep(2). It uses structure timespec that is used to specify intervals of time with nanosecond precision.

使用nanosleep(2)。它使用结构timespec,用于指定具有纳秒精度的时间间隔。

struct timespec {
           time_t tv_sec;        /* seconds */
           long   tv_nsec;       /* nanoseconds */
       };

#7


#! /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

#8


Since my previous answer I came up with another solution that is different and perhaps better. This code allows processes to be run more than 60 times a minute with microsecond precision. You need the usleep program to make this work. Should be good to up to 50 times a second.

自从我之前的回答以来,我提出了另一种不同的解决方案,也许更好。此代码允许进程以微秒精度每分钟运行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

#9


To avoid possible overlapping of execution, use a locking mechanism as described in that thread.

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

#1


I would use cron to run a script every minute, and make that script run your script four times with a 15-second sleep between runs.

我会每分钟使用cron运行一个脚本,并使该脚本运行您的脚本四次,运行之间的休眠时间为15秒。

(That assumes your script is quick to run - you could adjust the sleep times if not.)

(这假设您的脚本可以快速运行 - 如果没有,您可以调整睡眠时间。)

That way, you get all the benefits of cron as well as your 15 second run period.

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

Edit: See also @bmb's comment below.

编辑:另见@ bmb的评论如下。

#2


If you insist of running your script from cron:

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

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

and replace your script name&path to /foo/bar/your_script

并将您的脚本名称和路径替换为/ foo / bar / your_script

#3


Modified version of the above:

以上修改版:

mkdir /etc/cron.15sec
mkdir /etc/cron.minute
mkdir /etc/cron.5minute

add to /etc/crontab:

添加到/ 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

#4


Won't running this in the background do it?

不会在后台运行这个吗?

#!/bin/sh
while [ 1 ]; do
    echo "Hell yeah!" &
    sleep 15
done

This is about as efficient as it gets. The important part only gets executed every 15 seconds and the script sleeps the rest of the time (thus not wasting cycles).

这几乎和它一样高效。重要部分仅每15秒执行一次,脚本会在其余时间休眠(因此不会浪费周期)。

#5


I wrote a scheduler faster than cron. I have also implemented an overlapping guard. You can configure the scheduler to not start new process if previous one is still running. Take a look at https://github.com/sioux1977/scheduler/wiki

我写的调度程序比cron更快。我也实施了一个重叠的守卫。您可以将调度程序配置为在前一个进程仍在运行时不启动新进程。看看https://github.com/sioux1977/scheduler/wiki

#6


Use nanosleep(2). It uses structure timespec that is used to specify intervals of time with nanosecond precision.

使用nanosleep(2)。它使用结构timespec,用于指定具有纳秒精度的时间间隔。

struct timespec {
           time_t tv_sec;        /* seconds */
           long   tv_nsec;       /* nanoseconds */
       };

#7


#! /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

#8


Since my previous answer I came up with another solution that is different and perhaps better. This code allows processes to be run more than 60 times a minute with microsecond precision. You need the usleep program to make this work. Should be good to up to 50 times a second.

自从我之前的回答以来,我提出了另一种不同的解决方案,也许更好。此代码允许进程以微秒精度每分钟运行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

#9


To avoid possible overlapping of execution, use a locking mechanism as described in that thread.

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