Problem z $ RANDOM w crontab

9

Mam dziwny problem z $ RANDOM w cronie. Chcę wykonać polecenie losowo po kilku minutach od uruchomienia cronjob.

Ten przykład działa bezpośrednio w terminalu i opóźnia polecenie do 30 sekund (zamień polecenie na cokolwiek chcesz, w rzeczywistości jest to echo do / dev / ttyUSB0):

sleep `expr $RANDOM \% 30` ; command

Jeśli ta sama linia zostanie umieszczona w crontab, polecenie zawsze uruchamia się natychmiast bez opóźnienia:

* * * * * sleep `expr $RANDOM \% 30` ; command

Jeśli użyję wyrażenia bez $ RANDOM, działa dobrze - powoduje to opóźnienie 15 sekund:

* * * * * sleep `expr 10 + 5` ; command

Innymi słowy, wygląda na to, że $ RANDOM nie działa w cronie.

Ale to nie tylko dlatego, że $ RANDOM sam ocenia na zero, ponieważ wtedy powinno to dać opóźnienie 10:

* * * * * sleep `expr $RANDOM \% 30 + 10` ; command

Próbowałem też z && instread of; ale to nie pomaga. W rzeczywistości to polecenie wcale nie strzela!

Mógłbym oczywiście umieścić opóźnienie w skrypcie, który jest następnie wywoływany z crontab, ale to nie wyjaśnia mojego problemu i nie każe mi się uczyć :-)

To Debian Lenny, jeśli to robi jakąkolwiek różnicę.

marlar
źródło

Odpowiedzi:

18

cronużywa /bin/shpowłoki do wykonywania zadań. W niektórych dystrybucjach jest to dowiązanie symboliczne do dash. Żadna z nich nie obsługuje $RANDOMzmiennej, która jest bashrozszerzeniem -specyficznym.

  • Dzięki vixie-cron możesz umieścić linię SHELL=/bin/bashna górze swojego crontabu.

  • W przeciwnym razie będziesz musiał osiedlić się z bash -c 'echo $RANDOM'lub perl -e 'print int(rand(65535))'.

    (W powyższym przykładzie 65535 to maksymalna liczba do zwrócenia. Możesz również zastosować inną matematykę w skrypcie).

  • W prawidłowo skonfigurowanym systemie użytkownik zostałby o tym poinformowany cronsam - zawsze wysyła dane wyjściowe zadania, w tym komunikaty o błędach, pocztą elektroniczną. Zainstaluj lekki MTA.


Również w bash $(( ))jest preferowany `expr`.

użytkownik1686
źródło
Ostatnio sprawdziłem, że /bin/shnie była to rzeczywista powłoka, a jedynie dowiązanie symboliczne do preferowanej powłoki sysadmin (zwykle bash lub dash) na Debianie.
Hello71,
1
@ Hello71: Tak powiedziałem w poście. Niemniej jednak zwyczajowo oprogramowanie systemowe uruchamia się /bin/sh(i oczekuje, że będzie ono zgodne z powłoką Bourne'a). Przykładem jest system()funkcja w glibc. Dlatego /bin/shzwykle wskazuje na najszybszą powłokę kompatybilną z Bourne; a sysadmin powinien ustawić swoje preferencje we właściwej linii / etc / passwd, aby nie wymuszać tej preferencji w
całym
@ Hello71: ... dobrze, głównie to, co powiedziałem w poście. (Wiem, że większość innych dystrybucji prowadzi shdo linku bash, ale nie wydawało się to istotne.)
user1686,
Masz rację, /bin/shwskazuje na myślenie. Do tej pory nigdy nie słyszałem o desce rozdzielczej. Spojrzałem na to i jest to lekki wariant bash. Nie wiedziałem też, że cron działał w „kalekim” środowisku, ale wyjaśnia różne inne problemy, które miałem w przeszłości. Przy okazji, zacząłem używać, $(())ale ponieważ to nie zadziałało, wypróbowałem różne odmiany i ostatecznie skończyło się expr- co oczywiście też nie działało. Ale na tym skończyłem :-) Czy można uruchomić normalną powłokę bash bez użycia ograniczeń bash -c 'xxxx'? A tak przy okazji, czy nie można wstawiać podziałów linii w komentarzach?
marlar
@marlar: 1) dashjest powłoką. To nie jest mniej więcej normalne niż bash. To też nie jest wariant. 2) Patrz punkty 1 i 2 w odpowiedzi.
user1686,
2

cronzwykle działa w mniej „pełnym” środowisku, co oznacza, że ​​po prostu nie masz wielu takich samych zmiennych środowiskowych dostępnych. Podobno $RANDOMjest jednym z takich, w rzeczywistości twoja sleepkomenda jest po prostu braku z błędem z powodu zmiennej niezdefiniowanej - czyli dlaczego komenda nie działać w ogóle, kiedy włącza się &&zamiast ;. (Cóż, w rzeczywistości $RANDOMjest funkcją Bash, ale cronnie działa w pełnym środowisku Bash, w którym ewidentnie brakuje tej funkcji).

Aby wykonać to zadanie, musisz, jak powiedziałeś, użyć osobnego skryptu Bash. Alternatywnie możesz być w stanie wymyślić sposób użycia cat /dev/urandombezpośrednio w cronpoleceniu, ale prawdopodobnie łatwiej byłoby po prostu przenieść to, co aktualnie masz, do osobnego skryptu Bash.

Kromey
źródło
1
To nie jest ładne, ale znalazłem to rozwiązanie, które jest analogiczne do twojej sugestii: sleep $ (expr od -An -N1 -i /dev/urandom\% 30); polecenie
marlar
1
$RANDOMnie jest częścią „pełnego” środowiska. Nie ma to nic wspólnego ze zmiennymi środowiskowymi ustawionymi na początku procesu. Jest to specjalna zmienna stworzona „w locie” w bash. Jego nowa wartość jest zawsze generowana za każdym razem, gdy odczytywana jest zmienna. --- crondomyślnie używa, /bin/shwięc systemy, z którymi /bin/shnie jest powiązany bash $RANDOM, nie będą domyślnie działać.
pabouk