2009-06-23 37 views
77

Tôi đã nhìn thấy một vài giải pháp, bao gồm cả đồng hồ và chỉ đơn giản là chạy một kịch bản lặp (và ngủ) trong nền, nhưng không có gì là lý tưởng.Làm thế nào để có được một kịch bản Unix để chạy mỗi 15 giây?

Tôi có một tập lệnh cần chạy 15 giây một lần và vì cron không hỗ trợ giây, tôi còn lại để tìm ra một thứ khác.

Cách mạnh mẽ và hiệu quả nhất để chạy tập lệnh sau mỗi 15 giây trên Unix là gì? Tập lệnh cũng cần chạy sau khi khởi động lại.

+1

Mất bao lâu để chạy? –

Trả lời

73

Tôi sẽ sử dụng cron để chạy tập lệnh mỗi phút và làm cho tập lệnh đó chạy tập lệnh của bạn bốn lần với giấc ngủ 15 giây giữa các lần chạy.

(Đó giả kịch bản của bạn là nhanh chóng để chạy - bạn có thể điều chỉnh thời gian ngủ nếu không muốn nói.)

Bằng cách đó, bạn sẽ có được tất cả những lợi ích của cron cũng như 15 giai đoạn chạy thứ hai của bạn.

Chỉnh sửa: Xem thêm nhận xét của @ bmb bên dưới.

+0

* lắc nắm tay * hehe –

+0

@Aiden: Ha! Nemesis của tôi, chúng tôi gặp lại! – RichieHindle

+50

Nếu tập lệnh không nhất quán trong bao lâu để chạy, hãy tạo bốn bản sao của tập lệnh. Một người ngủ 15 giây trước khi bắt đầu, 30 giây khác, 45 giây khác và một số không. Sau đó chạy hết bốn phút một lần. – bmb

13

Sẽ không chạy tính năng này ở chế độ nền?

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

Tính năng này hiệu quả. Phần quan trọng chỉ được thực hiện sau mỗi 15 giây và tập lệnh ngủ trong suốt thời gian còn lại (do đó không làm lãng phí các chu kỳ).

+7

Chỉnh sửa phải có ít nhất 8 ký tự (tức là ngu ngốc, IMHO) vì vậy tôi không thể thêm '&' vào cuối dòng 3. Trong mọi trường hợp, như vậy, điều này không chạy mỗi 15 giây. Điều này chạy mỗi "15 giây + tuy nhiên dài' echo hello' mất để chạy ". Có thể là 0,01 giây; có thể là 19 giờ. –

257

Nếu bạn cứ khăng khăng chạy script của bạn từ cron:

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

và thay thế tên kịch bản của bạn & đường dẫn đến/foo/bar/your_script

+16

điều này rất thông minh. +1 – SingleNegationElimination

+4

Điều này làm việc hoàn hảo cho tôi. Lời giải thích trên đây về việc sử dụng một tác vụ nền đã sinh ra một số tiến trình con và gây ra các vấn đề về bộ nhớ trên đầu của tôi. – Hacknightly

+2

nếu chạy tập lệnh php thực hiện việc này: '* * * * * ngủ 15; php/foo/bar/your_script' – ImaginedDesign

0

Sử dụng nanosleep(2). Nó sử dụng cấu trúc timespec được sử dụng để xác định khoảng thời gian với độ chính xác nano giây.

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

Tôi sẽ tiếp tục và đoán chúng không cần độ chính xác nano giây, vì điều chúng sinh ra mỗi 15 giây là một kịch bản lệnh shell chứ không phải là một chuỗi hạt nhân. –

+0

@ParthianShot có thể nhưng bạn không bao giờ biết. –

-2

Để tránh chồng chéo thực thi, hãy sử dụng cơ chế khóa như được mô tả trong đó thread.

+2

-1 OP không nói rằng anh ta cần tránh thực thi chồng chéo; điều có thể là reentrant. Thêm vào đó, điều này không trả lời câu hỏi. –

+0

Điều này sẽ là một bình luận tốt đẹp, tôi sẽ upvote –

14

phiên bản thay đổi những điều trên:

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

thêm vào/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

Kể từ khi câu trả lời trước của tôi, tôi đã đưa ra một giải pháp đó là khác nhau và có lẽ tốt hơn . Mã này cho phép các quy trình được chạy hơn 60 lần một phút với độ chính xác micro giây. Bạn cần chương trình ngủ để thực hiện công việc này. Nên tốt đến 50 lần mỗi giây.

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

Chỉnh sửa bản gốc thay vì đăng lại! –

1

Tôi đã viết bộ lập lịch nhanh hơn cron. Tôi cũng đã thực hiện một bảo vệ chồng chéo. Bạn có thể cấu hình bộ lập lịch để không bắt đầu quá trình mới nếu quá trình trước đó vẫn đang chạy. Hãy xem https://github.com/sioux1977/scheduler/wiki

Các vấn đề liên quan