Jak mogę programowo utworzyć nowe zadanie cron?


133

Chcę mieć możliwość programowego dodawania nowego zadania cron, jaki jest najlepszy sposób, aby to zrobić?

Z moich badań wynika, że ​​mógłbym zrzucić bieżący plik crontab, a następnie dołączyć nowy, przesyłając go z powrotem do pliku crontab:

(crontab -l ; echo "0 * * * * wget -O - -q http://www.example.com/cron.php") | crontab -

Czy jest lepszy sposób?


2
Twoje rozwiązanie wydaje się dobre.
Craig S

W Solarisie po prostu usuń kreskę z ostatniego pliku crontab. Możesz dodać grep, aby uniknąć dodawania już tam linii.
lacroix1547


nawiasy klamrowe zamiast nawiasów zrobią to bez tworzenia procesu. Pamiętaj, aby zachować odstępy wokół nawiasów klamrowych, {...; }.
Jay Winston

Odpowiedzi:


-24

Zawsze mi się to udawało.

Powinieneś rozważyć nieco bardziej wyrafinowany skrypt, który może zrobić trzy rzeczy.

  1. Dołącz linię crontab; zapewniając, że nie istnieje. Dodawanie, gdy już istnieje, jest złe.

  2. Usuń linię crontab. Może tylko ostrzeżenie, jeśli nie istnieje.

  3. Połączenie powyższych dwóch funkcji, aby zastąpić linię crontab.


79
Pyta jak, a ty mu powiedz co?
Cerin

1
Co jeśli użytkownik nie ma jeszcze tabeli crontab?
Maxim Egorushkin

135

Najlepszym sposobem, jeśli pracujesz jako root, jest upuszczenie pliku do /etc/cron.d

jeśli używasz menedżera pakietów do pakowania oprogramowania, możesz po prostu umieścić pliki w tym katalogu i są one interpretowane tak, jakby były plikami crontab, ale z dodatkowym polem na nazwę użytkownika, np .:

Nazwa pliku: /etc/cron.d/per_minute

Zadowolony: * * * * * root /bin/sh /home/root/script.sh


5
Po prostu upewnij się, że używana wersja crona obsługuje /etc/cron.d/. Większość współczesnych dystrybucji Linuksa tak.
sleske

8
To najprostsze, najbardziej eleganckie rozwiązanie. Z pewnością pokonuje konieczność analizowania i edytowania istniejącej tabeli crontab z innymi niepowiązanymi wpisami.
Cerin

13
Jedynym potencjalnym zastrzeżeniem jest częstotliwość, z jaką cron pobiera nowe dodatki do tego folderu (raz na godzinę). Jeśli spodziewasz się, że Twoja praca zacznie działać od razu, uważaj.
JonathanK

6
@JonathanK, czy wiesz, czy cron może zostać poproszony o ponowne skanowanie /etc/cron.d/*? Trudno stwierdzić, czy coś działa, jeśli trzeba czekać godzinę na sprawdzenie!
halfer

4
jak ustawić uprawnienia dla tego pliku? chmod + x /etc/cron.d/per_minute?
giò

104

Rozwiązanie OP ma błąd, może pozwolić na dwukrotne dodanie wpisów, użyj poniżej, aby naprawić.

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -

5
W rzeczywistości jest to lepsze, jeśli nie opisane rozwiązanie. Zapewnia, że ​​polecenie nie jest dodawane dwukrotnie do crontab.
Bufke

2
Nie jest to dobre rozwiązanie problemu zduplikowanych wpisów. Co by było, gdyby w międzyczasie do crontaba została dodana inna linia?
hmn

6
Dla zapewnienia wyjątkowości, tuż sortprzed uniqnp .:(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
mway

6
Nie ma potrzeby uniq. Użyj -uopcji na sort.
papiro

7
jak uniknąć braku crontab dla użytkownika, kiedy po raz pierwszy edytuję crontab.
wyx

24

Dodać coś do crona

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -

Aby usunąć to z cron

(crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | grep -v hupChannel.sh |  sort | uniq | crontab -

nadzieja pomogłaby komuś


To jest dokładnie to, czego szukałem, dodałbym tylko: | grep -v '^ #' | aby odfiltrować komentarze
Tjunkie

3
Właściwie nie powinieneś tego potrzebować, 2>&1 | grep -v "no crontab"ponieważ gdy nie ma tabeli crontab, linia wyjściowa crontab: no crontab for...jest wysyłana do stderr. Nie ma powodu, aby przechwytywać te dane wyjściowe, wysyłać je na standardowe wyjście, a następnie filtrować je za pomocą grep. Jeśli Twoim celem jest uniknięcie patrzenia crontab: no crontab for...na wynik, użyj 2> /dev/null | sort.....
matty

8

Większość rozwiązań tutaj dotyczy dodawania linii do tabeli crontab. Jeśli potrzebujesz większej kontroli, będziesz chciał mieć możliwość kontrolowania całej zawartości tabeli crontab.

Możesz użyć orurowania, aby zrobić to całkiem elegancko.

Aby całkowicie przepisać plik crontab, zrób

echo "2 2 2 2 2 /bin/echo foobar" |crontab -

Powinno to być łatwe do połączenia z innymi opisanymi tutaj odpowiedziami, takimi jak

crontab -l | <something> | tee |crontab -

Lub, jeśli masz zawartość w pliku, jest to jeszcze prostsze

cat <file> |crontab -


6

Po prostu zmień edytor na tee polecenie:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e

4
Uważaj - to usuwa wszystkie istniejące wpisy.
starfry

5

Zakładając, że w twojej tabeli crontab znajduje się już wpis, poniższe polecenie powinno działać stosunkowo dobrze. Zauważ, że $CMDzmienna jest tam tylko dla czytelności. Sortowanie przed odfiltrowaniem duplikatów jest ważne, ponieważ uniqdziała tylko na sąsiednich wierszach.

CMD='wget -O - -q http://www.example.com/cron.php"'
(crontab -l ; echo "0 * * * * $CMD") | sort | uniq | crontab -

Jeśli obecnie masz pustą tabelę crontab, na stderr pojawi się następujący błąd:

no crontab for user

Jeśli chcesz tego uniknąć, możesz dodać trochę złożoności dodaj zrób coś takiego:

(crontab -l ; echo "0 * * * * $CMD") 2>&1 | sed "s/no crontab for $(whoami)//"  | sort | uniq | crontab -

3

Oto inny jednoliniowy sposób, który pozwala uniknąć duplikatów

(crontab -l 2>/dev/null | fgrep -v "*/1 *  *  *  * your_command"; echo "*/1 *  *  *  * your_command") | crontab -

A oto sposób na odpowiedź JohnZ i uniknięcie no crontab for userkomunikatu lub jeśli musisz działać w set -euśrodowisku typu i nie możesz mieć nic zwracającego błąd (w takim przypadku 2>/dev/nullczęść jest opcjonalna):

( (crontab -l 2>/dev/null || echo "")  ; echo "0 * * * * your_command") | sort -u - | crontab -

Lub jeśli chcesz podzielić rzeczy, aby były bardziej czytelne:

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
(echo "$preceding_cron_jobs" ; echo "$new_job") | sort - | uniq - | crontab -

Lub opcjonalnie usuń wszelkie odniesienia do komendy twoja_polecenie (np. Jeśli harmonogram się zmienił, chcesz, aby był on kiedykolwiek cron'owany tylko raz). W tym przypadku już nie potrzebujemy uniq(dodatkowy bonus, kolejność reklamowa jest również zachowana):

new_job="0 * * * * your_command"
preceding_cron_jobs=$(crontab -l || echo "")
preceding_cron_jobs=$(echo "$preceding_cron_jobs" | grep -v your_command )
(echo "$preceding_cron_jobs" ; echo "$new_job") | crontab -

2

man crontab jest również przydatny:

CRONTAB (1)

NAZWA

   crontab - manipulate per-user crontabs (Dillon's Cron)

STRESZCZENIE

   crontab file [-u user] - replace crontab from file

   crontab - [-u user] - replace crontab from stdin

   crontab -l [user] - list crontab for user

3
Część, która mówi "zamień crontab na stdin" to właściwie połowa odpowiedzi :-)
Grodriguez

2

Dodając do odpowiedzi JohnZ, oto składnia planowania jako root, jeśli jesteś sudoerem:

(sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -

1
function cronjob_exists($command){

    $cronjob_exists=false;

    exec('crontab -l', $crontab);


    if(isset($crontab)&&is_array($crontab)){

        $crontab = array_flip($crontab);

        if(isset($crontab[$command])){

            $cronjob_exists=true;

        }

    }
    return $cronjob_exists;
}

function append_cronjob($command){

    if(is_string($command)&&!empty($command)&&cronjob_exists($command)===FALSE){

        //add job to crontab
        exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output);


    }

    return $output;
}

    append_cronjob('* * * * * curl -s http://localhost/cron/test.php');

1

Spowoduje to sprawdzenie, czy polecenie nie istnieje przed jego dodaniem.

crontab -l 2>/dev/null | grep -q '/path/to/script' || echo "5 * * * * /path/to/script" | crontab -

Twoje zdrowie.


0

Piping stdout into crontabnie zainstalował dla mnie nowego crontab na macOS, więc zamiast tego znalazłem to rozwiązanie, używając teeedytora w powłoce podrzędnej:

(EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)

0

Jeśli chcesz, aby zadanie było uruchamiane jako użytkownik:

crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | crontab -

Jeśli chcesz, aby zadanie było uruchamiane z uprawnieniami:

sudo crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | sudo crontab -

i sprawdź zadanie (z lub bez 'sudo'):

crontab -l | sed '/^$/d; /#/d'

0

Poniżej przedstawiam to, czego używam w swoim skrypcie

1.

(2>/dev/null crontab -l ; echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -
cat <(crontab -l 2>/dev/null) <(echo "0 3 * * * /usr/local/bin/certbot-auto renew") | crontab -

# wypisz aktualną tabelę crontab

crontab -l > mycron 2>/dev/null

#echo nowy cron do pliku cron

echo "0 3 * * * /usr/local/bin/certbot-auto renew" >> mycron

# zainstaluj nowy plik cron

crontab mycron

rm mycron


-2

Możesz również edytować plik tekstowy tabeli cron bezpośrednio, ale Twoje rozwiązanie wydaje się całkowicie akceptowalne.


1
Byłbym nieufny wobec tego z powodu obaw o możliwość jednoczesnych edycji powodujących uszkodzenie plików. Użycie polecenia crontab wiersza poleceń powinno uniknąć tego problemu.
Craig S

Craig, bez dalszych badań nie byłbym pewien, czy wersja wiersza poleceń jest atomowa i bezpieczna w warunkach wyścigu. Prawdopodobnie w każdym razie „całkiem bezpieczny”.
tuomassalo

"Edycja pliku bezpośrednio" nie jest możliwa bez uprawnień administratora (pod warunkiem, że możesz dowiedzieć się, gdzie znajduje się plik crontab użytkownika i jak upewnić się, że demon cron poprawnie odbiera twoje zmiany), a "edycja" programistyczna wydaje się być tym, o co chodzi przede wszystkim potrzebuje porady.
tripleee
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.