Jak symulować środowisko, z którym cron wykonuje skrypt?


253

Zwykle mam kilka problemów z tym, jak cron wykonuje skrypty, ponieważ normalnie nie mają konfiguracji mojego środowiska. Czy istnieje sposób na wywołanie bash (?) W taki sam sposób, jak robi to cron, aby móc przetestować skrypty przed ich zainstalowaniem?


Sugerowałbym to rozwiązanie: unix.stackexchange.com/questions/27289/…
rudi

Posuwając @gregseth nieco dalej, podałem to rozwiązanie: unix.stackexchange.com/questions/27289/…
Robert Brisita,

Odpowiedzi:


385

Dodaj to do swojego crontab (tymczasowo):

* * * * * env > ~/cronenv

Po uruchomieniu wykonaj następujące czynności:

env - `cat ~/cronenv` /bin/sh

Zakłada się, że twój cron działa / bin / sh, który jest domyślny niezależnie od domyślnej powłoki użytkownika.


5
Uwaga: jeśli dodajesz to do globalnego pliku / etc / crontab, potrzebujesz również nazwy użytkownika. Np. * * * * * Root env> ~ / cronenv
Greg

10
Dobry, prosty pomysł. Aby niecierpliwie użyć „* * * * *”, aby uruchomić w następnej minucie, i pamiętaj, aby wyłączyć ponownie, gdy skończysz grać ;-)
Mads Buus

5
@Madsn Aby powrócić do poprzedniej powłoki bash, spróbuj: exit
spkane

5
Nie można nie doceniać znaczenia tej odpowiedzi. Warto dodać akapit do książki.
Xofo

1
czy env - cat ~ / cronenv` / bin / sh` powinien być również zapisany jako zadanie cron? podaj przykład
JavaSa

61

Cron domyślnie udostępnia tylko to środowisko:

  • HOME katalog domowy użytkownika
  • LOGNAME login użytkownika
  • PATH=/usr/bin:/usr/sbin
  • SHELL=/usr/bin/sh

Jeśli potrzebujesz więcej, możesz zdobyć skrypt, w którym zdefiniujesz środowisko przed tabelą harmonogramu w tabeli crontab.


7
.zwykle nie jest częścią PATHjuż, dla względów bezpieczeństwa .
l0b0

49

Kilka podejść:

  1. Wyeksportuj cron env i zrób to

    Dodaj

    * * * * * env > ~/cronenv

    na swoim crontabie, pozwól mu raz uruchomić, wyłącz go z powrotem, a następnie biegnij

    env - `cat ~/cronenv` /bin/sh

    Jesteś teraz w shsesji ze środowiskiem crona

  2. Doprowadź swoje środowisko do crona

    Możesz pominąć ćwiczenie i po prostu zrobić . ~/.profileprzed swoją pracą crona, np

    * * * * * . ~/.profile; your_command
  3. Użyj ekranu

    Powyższe dwa rozwiązania wciąż zawodzą, ponieważ zapewniają środowisko połączone z działającą sesją X, z dostępem do dbusitp. Na przykład w Ubuntu nmcli(Network Manager) będzie działał w dwóch powyższych podejściach, ale nadal zawiedzie w cron.

    * * * * * /usr/bin/screen -dm

    Dodaj powyższą linię do crona, pozwól jej uruchomić się raz, wyłącz go z powrotem. Połącz się z sesją ekranową (screen -r). Jeśli sprawdzasz, czy sesja ekranowa została utworzona (z ps), pamiętaj, że czasami są wielkimi literami (np. ps | grep SCREEN)

    Teraz nawet nmclii podobne zawiodą.


22

Możesz uruchomić:

env - your_command arguments

Spowoduje to uruchomienie komendy z pustym środowiskiem.


4
cron nie działa w całkowicie pustym środowisku, prawda?
jldupont

2
gregseth zidentyfikował zmienne zawarte w środowisku przez crona. Możesz uwzględnić te zmienne w wierszu poleceń. $ env - PATH =
Argument

4
@DragonFax @dimba Używam, env - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command argumentsco wydaje się załatwić
sprawę

Jest to świetna prosta metoda testowania skryptów w „wrogim” lub nieznanym środowisku. Jeśli masz wystarczającą jasność, że będzie w tym działać, będzie działał pod cronem.
Oli


13

Odpowiedź sześć lat później: problem niedopasowania środowiska jest jednym z problemów rozwiązanych przez systemd„timery” jako zamiennik crona. Niezależnie od tego, czy uruchamiasz systemową „usługę” z interfejsu CLI, czy za pośrednictwem crona, otrzymuje on dokładnie to samo środowisko, unikając problemu niedopasowania środowiska.

Najczęstszym problemem powodującym niepowodzenie zadań cron po ich ręcznym przekazaniu jest restrykcyjne ustawienie domyślne $PATHustawione przez crona, takie jak w Ubuntu 16.04:

"/usr/bin:/bin"

Natomiast domyślnym $PATHustawieniem systemddla Ubuntu 16.04 jest:

"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Jest więc już większa szansa, że ​​systemowy licznik znajdzie plik binarny bez dalszych kłopotów.

Wadą systemowych timerów jest nieco więcej czasu na ich konfigurację. Najpierw tworzysz plik „usługi”, aby zdefiniować, co chcesz uruchomić, i plik „timera”, aby zdefiniować harmonogram uruchamiania, a na koniec „włączyć” timer, aby go aktywować.


10

Utwórz zadanie cron, które uruchamia env i przekierowuje standardowe wyjście do pliku. Użyj pliku obok „env -”, aby stworzyć to samo środowisko co zadanie cron.


Przepraszam, że to mnie zdezorientowało. nie wystarcza „env - skrypt”?
Jorge Vargas,

To da ci puste środowisko. Po uruchomieniu skryptów przez cron środowisko nie jest puste.
Jens Carlberg,


2

Domyślnie cronwykonuje zadania przy użyciu dowolnego pomysłu systemu sh. To może być rzeczywiste lub powłoki Bourne dash, ash, kshi bash(lub inny) dowiązane do sh(i w rezultacie działa w trybie POSIX).

Najlepiej jest upewnić się, że skrypty mają to, czego potrzebują, i założyć, że nic dla nich nie ma. Dlatego powinieneś używać pełnych specyfikacji katalogu i ustawiać zmienne środowiskowe, takie jak $PATHty.


Właśnie to próbuję rozwiązać. Mamy mnóstwo problemów ze skryptami, które zakładają coś przez pomyłkę. Robienie pełnych ścieżek i ustawianie zmiennych env i wszystkie śmieci kończą się straszliwymi, ogromnymi, niemożliwymi do utrzymania liniami cron
Jorge Vargas

re * sh przepraszam, że dorastałem z bash = shellem, więc trudno mi zapamiętać alternatywne (a czasem lepsze) powłoki.
Jorge Vargas,

1
@Jorge: wiersze w crontab powinny być dość krótkie. Powinieneś wykonać wszystkie potrzebne ustawienia w skrypcie (lub skrypcie opakowania). Oto typowy wiersz z pliku crontab jako przykład: 0 0 * * 1 /path/to/executable >/dev/null 2>&1a następnie w „wykonywalnym” ustawiłbym wartości dla $PATHitd. I użyłem pełnych specyfikacji katalogów do plików wejściowych i wyjściowych itp. Na przykład:/path/to/do_something /another/path/input_file /another/path/to/output_file
Wstrzymano do odwołania.

1

Innym prostym sposobem, który znalazłem (ale może być podatny na błędy, wciąż testuję) jest pozyskanie plików profilu użytkownika przed poleceniem.

Edycja skryptu /etc/cron.d/:

* * * * * user1 comand-that-needs-env-vars

Zmieniłoby się w:

* * * * * user1 source ~/.bash_profile; source ~/.bashrc; comand-that-needs-env-vars

Brudny, ale wykonał dla mnie robotę. Czy istnieje sposób na symulację logowania? Tylko polecenie, które możesz uruchomić? bash --loginnie działało Wygląda na to, że byłby to jednak lepszy sposób.

EDYCJA: To wydaje się być solidnym rozwiązaniem: http://www.epicserve.com/blog/2012/feb/7/my-notes-cron-directory-etccrond-ubuntu-1110/

* * * * * root su --session-command="comand-that-needs-env-vars" user1 -l

1

Zaakceptowana odpowiedź umożliwia uruchomienie skryptu w środowisku, którego używa cron. Jak zauważyli inni, nie jest to jedyne potrzebne kryterium do debugowania zadań cron.

Rzeczywiście, cron używa również nieinteraktywnego terminala, bez dołączonego wejścia itp.

Jeśli to pomoże, napisałem skrypt, który umożliwia bezbolesne uruchomienie polecenia / skryptu, tak jakby był uruchamiany przez crona. Wywołaj go za pomocą polecenia / skryptu jako pierwszego argumentu i jesteś dobry.

Ten skrypt jest również hostowany (i prawdopodobnie aktualizowany) w Github .

#!/bin/bash
# Run as if it was called from cron, that is to say:
#  * with a modified environment
#  * with a specific shell, which may or may not be bash
#  * without an attached input terminal
#  * in a non-interactive shell

function usage(){
    echo "$0 - Run a script or a command as it would be in a cron job, then display its output"
    echo "Usage:"
    echo "   $0 [command | script]"
}

if [ "$1" == "-h" -o "$1" == "--help" ]; then
    usage
    exit 0
fi

if [ $(whoami) != "root" ]; then
    echo "Only root is supported at the moment"
    exit 1
fi

# This file should contain the cron environment.
cron_env="/root/cron-env"
if [ ! -f "$cron_env" ]; then
    echo "Unable to find $cron_env"
    echo "To generate it, run \"/usr/bin/env > /root/cron-env\" as a cron job"
    exit 0
fi

# It will be a nightmare to expand "$@" inside a shell -c argument.
# Let's rather generate a string where we manually expand-and-quote the arguments
env_string="/usr/bin/env -i "
for envi in $(cat "$cron_env"); do
   env_string="${env_string} $envi "
done

cmd_string=""
for arg in "$@"; do
    cmd_string="${cmd_string} \"${arg}\" "
done

# Which shell should we use?
the_shell=$(grep -E "^SHELL=" /root/cron-env | sed 's/SHELL=//')
echo "Running with $the_shell the following command: $cmd_string"


# Let's route the output in a file
# and do not provide any input (so that the command is executed without an attached terminal)
so=$(mktemp "/tmp/fakecron.out.XXXX")
se=$(mktemp "/tmp/fakecron.err.XXXX")
"$the_shell" -c "$env_string $cmd_string" >"$so" 2>"$se" < /dev/null

echo -e "Done. Here is \033[1mstdout\033[0m:"
cat "$so"
echo -e "Done. Here is \033[1mstderr\033[0m:"
cat "$se"
rm "$so" "$se"

0

Odpowiedź https://stackoverflow.com/a/2546509/5593430 pokazuje, jak uzyskać środowisko cron i używać go w skrypcie. Należy jednak pamiętać, że środowisko może się różnić w zależności od używanego pliku crontab. Utworzyłem trzy różne wpisy cron, aby za pomocą zapisać środowisko env > log. Są to wyniki w Amazon Linux 4.4.35-33.55.amzn1.x86_64.

1. Globalny / etc / crontab z użytkownikiem root

MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
PWD=/
LANG=en_US.UTF-8
SHLVL=1
HOME=/
LOGNAME=root
_=/bin/env

2. Użytkownik crontab root ( crontab -e)

SHELL=/bin/sh
USER=root
PATH=/usr/bin:/bin
PWD=/root
LANG=en_US.UTF-8
SHLVL=1
HOME=/root
LOGNAME=root
_=/usr/bin/env

3. Skrypt w /etc/cron.hourly/

MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
_=/bin/env
PWD=/
LANG=en_US.UTF-8
SHLVL=3
HOME=/
LOGNAME=root

Co najważniejsze PATH, PWDa HOMEróżnią. Upewnij się, że ustawiłeś je w skryptach cron, aby opierały się na stabilnym środowisku.


-8

Nie wierzę w to; jedynym sposobem, w jaki wiem, aby przetestować zadanie crona, jest skonfigurowanie go do uruchomienia za minutę lub dwie w przyszłości, a następnie czekania.


Właśnie dlatego proszę symulować
Jorge Vargas
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.