Wykonuj skrypt bash dosłownie co 3 dni

8

Chcę wykonać skrypt powłoki dosłownie po każdych 3 dniach. Używanie crontab z 01 00 */3 * * nie spełni warunku, ponieważ będzie działał 31-go, a następnie znowu 1-go dnia miesiąca. Składnia */3 jest taka sama jak przy opisie 1,4,7 ... 25,28,31.

Powinny istnieć sposoby, aby sam skrypt sprawdził warunki i zakończył działanie, jeśli 3 dni nie minęły. Tak więc crontab wykonuje skrypt codziennie, ale sam skrypt sprawdzi, czy minęły 3 dni.

Znalazłem nawet kod, ale dał mi błąd składni, każda pomoc byłaby doceniana.

if (! (date("z") % 3)) {
     exit;
}

main.sh: line 1: syntax error near unexpected token '"z"'
main.sh: line 1: 'if (! (date("z") % 3)) {'
    
zadawane Taavi 25.09.2016, 14:36
źródło

5 odpowiedzi

12

Aby natychmiast przerwać i zamknąć skrypt, jeśli ostatnie wykonanie nie zostało jeszcze co najmniej w określonym czasie, możesz użyć tej metody, która wymaga zewnętrznego pliku przechowującego datę i godzinę ostatniego wykonania.

Dodaj te linie do początku skryptu Bash:

#!/bin/bash

# File that stores the last execution date in plain text:
datefile=/path/to/your/datefile

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Test if datefile exists and compare the difference between the stored date 
# and now with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test -f "$datefile" ; then
    if test "$(($(date "+%s")-$(date -f "$datefile" "+%s")))" -lt "$seconds" ; then
        echo "This script may not yet be started again."
        exit 1
    fi
fi

# Store the current date and time in datefile
date -R > "$datefile"

# Insert your normal script here:

Nie zapomnij ustawić znaczącej wartości jako datefile= i dopasuj wartość seconds= do swoich potrzeb ( $((60*60*24*3)) oznacza 3 dni).

Jeśli nie chcesz osobnego pliku, możesz również zapisać czas ostatniego wykonania w znaczniku czasu modyfikacji skryptu. Oznacza to jednak, że wszelkie zmiany w pliku skryptu zresetują 3 liczniki i będą traktowane tak, jakby skrypt działał poprawnie.

Aby to zaimplementować, dodaj poniższy fragment na górze pliku skryptu:

#!/bin/bash

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Compare the difference between this script's modification time stamp 
# and the current date with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test "$(($(date "+%s")-$(date -r "$0" "+%s")))" -lt "$seconds" ; then
    echo "This script may not yet be started again."
    exit 1
fi

# Store the current date as modification time stamp of this script file
touch -m -- "$0"

# Insert your normal script here:

Ponownie, nie zapomnij dostosować wartości seconds= do swoich potrzeb ( $((60*60*24*3)) oznacza 3 dni).

    
odpowiedział Byte Commander 25.09.2016, 15:20
źródło
12

Cron naprawdę jest niewłaściwym narzędziem do tego. W rzeczywistości istnieje powszechnie używane i niedopracowane narzędzie o nazwie at , które może działać. At głównie jest przeznaczony do użytku interaktywnego i jestem pewien, że ktoś znalazłby lepszy sposób na zrobienie tego.

W moim przypadku powinienem mieć skrypt, który mam uruchomiony w testjobs.txt, i zawierać wiersz, który czyta.

Jako przykład, mam to jako testjobs.txt

echo "cat" >> foo.txt
date >> foo.txt
at now + 3 days < testjobs.txt

Mam dwie niewinne komendy, które mogą być twoimi skoroszytami. Uruchomiłem echo, aby upewnić się, że mam deterministyczny wynik i datę, aby potwierdzić uruchamianie komendy w razie potrzeby. Gdy uruchomi to polecenie, zakończy się dodaniem nowego zadania do at na 3 dni. (Testowałem przez minutę - co działa)

Jestem prawie pewny, że będę wzywany za sposób, w jaki się nadużywałem, ale jest to przydatne narzędzie do planowania polecenia do wykonania w raz lub x dni po poprzednie polecenie.

    
odpowiedział Journeyman Geek 25.09.2016, 16:06
źródło
3

Po pierwsze, powyższy fragment kodu jest nieprawidłową składnią Basha, wygląda jak Perl. Po drugie, parametr z do date powoduje, że wyprowadza on numeryczną strefę czasową. +%j to numer dnia. Potrzebujesz:

if [[ ! $(( $(date +%j) % 3 )) ]] ;then
     exit
fi

Ale na koniec roku będziesz jeszcze dziwny:

$ for i in 364 365  1 ; do echo "Day $i, $(( $i % 3 ))"; done
Day 364, 1
Day 365, 2
Day 1, 1

Możesz mieć więcej szczęścia w utrzymywaniu liczby w pliku i testowaniu / aktualizowaniu tego.

    
odpowiedział waltinator 25.09.2016, 15:18
źródło
2

Jeśli możesz po prostu pozostawić skrypt działający wiecznie, możesz:

while true; do

[inert code here]

sleep 259200
done

Ta pętla jest zawsze prawdziwa, więc zawsze wykona kod, a następnie odczeka trzy dni przed ponownym uruchomieniem pętli.

    
odpowiedział mkingsbu 25.09.2016, 16:25
źródło
2

Możesz użyć anacron zamiast crona, jest zaprojektowany dokładnie tak, aby robić to, czego potrzebujesz. Ze strony podręcznika:

% bl0ck_qu0te%     
odpowiedział Twinkles 26.09.2016, 15:33
źródło

Przeczytaj inne pytania na temat tagów