2009-06-23 39 views
77

Widziałem kilka rozwiązań, w tym obejrzenie i po prostu uruchomienie skryptu pętli (i spania) w tle, ale nic nie było idealne.Jak uruchomić skrypt unixowy co 15 sekund?

Mam skrypt, który musi być uruchamiany co 15 sekund, a ponieważ cron nie będzie obsługiwał sekund, pozostawiam mi zadanie znalezienia czegoś innego.

Jaki jest najbardziej solidny i skuteczny sposób uruchamiania skryptu co 15 sekund w systemie UNIX? Skrypt musi również zostać uruchomiony po ponownym uruchomieniu komputera.

+1

Ile czasu zajmuje uruchomienie? –

Odpowiedz

73

Używałbym crona do uruchamiania skryptu co minutę, i sprawił, że skrypt uruchamiał twój skrypt czterokrotnie z 15-sekundowym snem pomiędzy przebiegami.

(który zakłada skrypt jest szybkie uruchomienie - można dostosować czas snu, czy nie).

W ten sposób można uzyskać wszystkie korzyści płynące z cron jak swój drugi okres 15 run.

Edytuj: Zobacz także komentarz @ bmb poniżej.

+0

* wstrząsa pięścią * hehe –

+0

@Aiden: Ha! Moja nemezis, znów się spotykamy! – RichieHindle

+50

Jeśli skrypt nie jest spójny w czasie działania, należy wykonać cztery kopie skryptu. Jedna osoba śpi 15 sekund przed startem, kolejne 30, kolejne 45 i kolejne zero. Następnie uruchamiaj wszystkie cztery co minutę. – bmb

13

Czy nie uruchomisz tego w tle?

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

To jest tak wydajne, jak to tylko możliwe. Ważna część jest wykonywana tylko co 15 sekund, a skrypt śpi przez resztę czasu (nie marnując cykli).

+7

Zmiany muszą mieć co najmniej 8 znaków (co jest idiotyczne, IMHO), więc nie mogłem dodać '&' na końcu linii 3. W każdym razie, tak jak jest, to nie działa co 15 sekund. To działa co "15 sekund + tak długo, jak długo' echo hello' trwa do uruchomienia ". Które może wynosić 0,01 sekundy; może być 19 godzin. –

257

Jeśli upierasz uruchamiać skrypt z cron:

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

i zastąpić nazwę skryptu & ścieżka/foo/bar/your_script

+16

to jest bardzo sprytne. +1 – SingleNegationElimination

+4

To działało idealnie dla mnie. Rozwiązanie powyżej tego przy użyciu zadania w tle powodowało powstawanie kilku procesów podrzędnych i powodowało problemy z pamięcią po mojej stronie. – Hacknightly

+2

jeśli uruchamiasz skrypt php: * * * * * sleep 15; php/foo/bar/your_script' – ImaginedDesign

0

Korzystanie nanosleep(2). Wykorzystuje strukturę timespec, która służy do określania odstępów czasu z dokładnością nanosekundową.

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

Zamierzam zgadywać, że nie potrzebują nanosekundowej precyzji, ponieważ rzecz, którą spawną co 15 sekund, to skrypt powłoki, a nie wątek jądra. –

+0

@ParthianShot być może, ale nigdy nie wiadomo. –

-2

Aby uniknąć możliwego nakładania się wykonania, należy użyć mechanizmu blokującego opisanego w tym thread.

+2

-1 PO nie powiedział, że musi unikać nakładania się egzekucji; rzecz może być wewnętrzna. Dodatkowo, to nie odpowiada na pytanie. –

+0

To byłby miły komentarz, chciałbym upvote –

14

Zmodyfikowana wersja powyższego:

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

dodać do pliku/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 
0
#! /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 
0

Od mojej poprzedniej odpowiedzi wymyśliłem innego rozwiązania, który jest różny i może lepiej . Ten kod pozwala na uruchamianie procesów ponad 60 razy na minutę z dokładnością mikrosekundową. Potrzebujesz programu usleep, aby to działało. Powinien być dobry do 50 razy na sekundę.

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

Edytuj oryginalny zamiast publikować ponownie! –

1

Napisałem program planujący szybciej niż cron. Wprowadziłem też nakładającego się strażnika. Możesz skonfigurować program planujący tak, aby nie uruchamiał nowego procesu, jeśli poprzedni nadal działa. Przejrzyj https://github.com/sioux1977/scheduler/wiki

Powiązane problemy