Jak zmusić CRON do wywoływania prawidłowych ścieżek

125

Próbuję zmusić crona do wywołania prawidłowych PATH. Kiedy uruchamiam skrypt Pythona z powłoki, skrypt działa dobrze, ponieważ używa PATH ustawionych w bashrc, ale kiedy używam crona, wszystkie PATH nie są używane z bashrc. Czy istnieje plik, do którego mogę wprowadzić PATH dla crona, taki jak bashrc lub sposób na wywołanie PATH z bashrc?

Przepraszam, nie wydaje mi się, żebym to poprawnie sformułował, mogę uruchomić poprawny skrypt do uruchomienia (co oznacza, że ​​PATH do skryptu w crontab nie jest tutaj problemem), tylko wtedy, gdy ten skrypt jest uruchomiony, uruchamiam kompilację i używa PATHs ustawione .bashrc. Kiedy uruchamiam skrypt, gdy jestem zalogowany, .bashrcPATH są pobierane. Ponieważ cron nie działa w powłoce, powiedzmy, nie pobiera .bashrc. Czy istnieje sposób, aby to zrobić bez konieczności pisania opakowania skryptu bash?

chrissygormley
źródło
zapoznaj się również z sugestią podaną tutaj, aby dowiedzieć się, jak ustawić ustawienia bashrc, aby działały w cronjobs: stackoverflow.com/q/15557777/1025391
moooeeeep
2
Magiczne, proste i poprawne polecenie włączenia profilu do obecnego środowiska polega na tym source /etc/profile, że powinien jeść .bashrci wiele innych potencjalnie brakujących rzeczy. Jawne pozyskiwanie profili staje się całkiem przydatne, jeśli chcesz, aby niektóre skrypty działały „samodzielnie”, chronią również przed dziwnymi środowiskami, a więc ...
exa
1
@exa +100 To sprawia, że shskrypty wywoływane przez crontab działają. Możesz potwierdzić, że aktualizuje ścieżkę, dodając zadanie * * * * * echo $PATH > ~/crontab_path.txti sprawdzając plik po minucie.
geoteoria

Odpowiedzi:

177

Użyłem /etc/crontab. Użyłem vii wprowadziłem PATH, których potrzebowałem, do tego pliku i uruchomiłem go jako root. Normalny plik crontab nadpisuje skonfigurowane przez ciebie PATH. Dobry poradnik, jak to zrobić .

Ogólnosystemowy plik cron wygląda następująco:

This has the username field, as used by /etc/crontab.
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file.
# This file also has a username field, that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user   command
42 6 * * *   root    run-parts --report /etc/cron.daily
47 6 * * 7   root    run-parts --report /etc/cron.weekly
52 6 1 * *   root    run-parts --report /etc/cron.monthly
01 01 * * 1-5 root python /path/to/file.py
chrissygormley
źródło
17
Działa to z crontab -e na poziomie użytkownika i jest też bezpieczniejsze.
Robert Brisita,
2
Czy mogę używać basha zamiast sh?
Qed
1
dziwne jest (dla mnie), że domyślna PATH ustawiona w / etc / crontab, jak pokazano przez @chrissygormley, a także ustawiona w mojej tabeli crontab (Ubuntu), różni się od ścieżki w / etc / environment, w szczególności umieszcza / sbin i / bin przed / usr / sbin i / usr / bin. Teraz zmieniłem to w moim / etc / crontab, aby było takie samo jak środowisko użytkownika.
scoobydoo
Nie działa dla mnie .. Wysyłam zawartość crona do pliku. Cron działa, plik tworzy, ale nie umieszcza w nim żadnej zawartości.
Volatil3
2
Wygląda na to, że nie wszystkie ustawione ścieżki /etc/crontabsą dostępne dla crona, gdy działa jako root w Ubuntu 14.04. ( sudo crontab -e)
David Oliver
50

Najprawdopodobniej cron działa w bardzo rzadkim środowisku. Sprawdź zmienne środowiskowe, których używa cron, dołączając fikcyjne zadanie, które zrzuca envdo pliku takiego jak ten:

* * * * * env > env_dump.txt

Porównaj to z danymi wyjściowymi envw normalnej sesji powłoki.

Możesz dołączyć własne zmienne środowiskowe do lokalnej tabeli crontab, definiując je na górze swojej tabeli crontab.

Oto szybka poprawka do dodania $PATHprzed bieżącą tabelą crontab:

# echo PATH=$PATH > tmp.cron
# echo >> tmp.cron
# crontab -l >> tmp.cron
# crontab tmp.cron

Wynikowy plik crontab będzie wyglądał podobnie do odpowiedzi chrissygormley, z PATH zdefiniowaną przed regułami tabeli crontab.

joemaller
źródło
22

Powinieneś umieścić pełne ścieżki w swoim crontab. To najbezpieczniejsza opcja.
Jeśli nie chcesz tego robić, możesz umieścić skrypt opakowujący wokół swoich programów i ustawić tam PATH.

na przykład

01 01 * * * command

staje się:

01 01 * * * /full/path/to/command

Również wszystko wywoływane z cronpowinno być bardzo ostrożne w przypadku programów, które uruchamia i prawdopodobnie ustawiać własny wybór dla PATHzmiennej.

EDYTOWAĆ:

Jeśli nie wiesz, gdzie jest polecenie, które chcesz wykonać which <command> ze swojej powłoki, wskaże ci ścieżkę.

EDYCJA2:

Po uruchomieniu programu pierwszą rzeczą, jaką powinien zrobić, jest ustawienie PATHi każdej innej wymaganej zmiennej (np. LD_LIBRARY_PATH) Wartości wymaganych do uruchomienia skryptu.
Zasadniczo zamiast zastanawiać się, jak zmodyfikować środowisko cron, aby było bardziej odpowiednie dla twojego programu / skryptu - spraw, aby twój skrypt obsługiwał dane środowisko, ustawiając odpowiednie podczas uruchamiania.

Douglas Leeder
źródło
1
jeśli jest na twojej ścieżce, użyj
Paul Whelan
@Douglas Leeder - Kiedy mówisz, że umieść pełną ścieżkę w cronie, czy masz na myśli umieścić ją w crontab lub innym pliku? Jeśli tak, jak byś się do tego zabrał, gdyby polecenie cron brzmiało: '01 01 * * * command '. Dzięki
chrissygormley
@chrissygormley - Yes crontab.
Douglas Leeder
Przepraszam, musi być trochę zamieszania. Przeformułowałem powyższe pytanie.
chrissygormley
16

Ustawienie PATH tuż przed wierszem poleceń w moim pliku crontab działało dla mnie:

* * * * * PATH=$PATH:/usr/local/bin:/path/to/some/thing
myrho
źródło
wolą ten sposób. lub podaj pełną ścieżkę do skryptu.
zw963
5
Nie sądzę, aby ścieżka się rozwijała, za każdym razem będzie działać w nowym środowisku, ze świeżą kopią PATH ...
jjcf89
Potwierdza, że ​​@ jjcf89 jest poprawne, a PATH jest aktualna przy każdym uruchomieniu.
electrovir
14

Dodanie definicji PATH do crontab użytkownika z poprawnymi wartościami pomoże ... Wypełniłem moją tylko:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

I to wystarczy, aby wszystkie moje skrypty działały ... Dołącz tam dowolną niestandardową ścieżkę, jeśli potrzebujesz.

Treviño
źródło
1
Dla użytkownika crontab to powinna być poprawna odpowiedź. Nie każdy w systemie może edytować /etc/crontab. To najłatwiejsza odpowiedź na poziomie użytkownika. Dobra robota @ Treviño. Zagłosuj na to, jeśli się zgadzasz.
frederickjh
14

Spraw, aby Twoje zmienne działały za Ciebie, umożliwi to dostęp do t

Zdefiniuj swoją ŚCIEŻKĘ w /etc/profile.d/*.sh

Zmienne środowiskowe dla całego systemu

Pliki z rozszerzeniem .sh w katalogu /etc/profile.d są wykonywane za każdym razem, gdy zostanie wprowadzona powłoka logowania bash (np. Podczas logowania z konsoli lub przez ssh), a także przez DisplayManager podczas ładowania sesji pulpitu.

Możesz na przykład utworzyć plik /etc/profile.d/myenvvars.sh i ustawić zmienne w następujący sposób:

export JAVA_HOME=/usr/lib/jvm/jdk1.7.0
export PATH=$PATH:$JAVA_HOME/bin

Uruchom crontab z opcją logowania!

CRONTAB uruchamia skrypt lub polecenie ze zmiennymi środowiskowymi

0 9 * * * cd /var/www/vhosts/foo/crons/; bash -l -c 'php -f ./download.php'
0 9 * * * cd /var/www/vhosts/foo/crons/; bash -l -c download.sh
Artistan
źródło
11

Problem

Twój skrypt działa, gdy uruchamiasz go z konsoli, ale nie działa w cronie.

Przyczyna

Twój plik crontab nie ma odpowiednich zmiennych ścieżki (i prawdopodobnie powłoki)

Rozwiązanie

Dodaj aktualną powłokę i ścieżkę do pliku crontab

Skrypt, który zrobi to za Ciebie

#!/bin/bash
#
# Date: August 22, 2013
# Author: Steve Stonebraker
# File: add_current_shell_and_path_to_crontab.sh
# Description: Add current user's shell and path to crontab
# Source: http://brakertech.com/add-current-path-to-crontab
# Github: hhttps://github.com/ssstonebraker/braker-scripts/blob/master/working-scripts/add_current_shell_and_path_to_crontab.sh

# function that is called when the script exits (cleans up our tmp.cron file)
function finish { [ -e "tmp.cron" ] && rm tmp.cron; }

#whenver the script exits call the function "finish"
trap finish EXIT

########################################
# pretty printing functions
function print_status { echo -e "\x1B[01;34m[*]\x1B[0m $1"; }
function print_good { echo -e "\x1B[01;32m[*]\x1B[0m $1"; }
function print_error { echo -e "\x1B[01;31m[*]\x1B[0m $1"; }
function print_notification { echo -e "\x1B[01;33m[*]\x1B[0m $1"; }
function printline { 
  hr=-------------------------------------------------------------------------------------------------------------------------------
  printf '%s\n' "${hr:0:${COLUMNS:-$(tput cols)}}"
}
####################################
# print message and exit program
function die { print_error "$1"; exit 1; }

####################################
# user must have at least one job in their crontab
function require_gt1_user_crontab_job {
        crontab -l &> /dev/null
        [ $? -ne 0 ] && die "Script requires you have at least one user crontab job!"
}


####################################
# Add current shell and path to user's crontab
function add_shell_path_to_crontab {
    #print info about what's being added
    print_notification "Current SHELL: ${SHELL}"
    print_notification "Current PATH: ${PATH}"

    #Add current shell and path to crontab
    print_status "Adding current SHELL and PATH to crontab \nold crontab:"

    printline; crontab -l; printline

    #keep old comments but start new crontab file
    crontab -l | grep "^#" > tmp.cron

    #Add our current shell and path to the new crontab file
    echo -e "SHELL=${SHELL}\nPATH=${PATH}\n" >> tmp.cron 

    #Add old crontab entries but ignore comments or any shell or path statements
    crontab -l | grep -v "^#" | grep -v "SHELL" | grep -v "PATH" >> tmp.cron

    #load up the new crontab we just created
    crontab tmp.cron

    #Display new crontab
    print_good "New crontab:"
    printline; crontab -l; printline
}

require_gt1_user_crontab_job
add_shell_path_to_crontab

Źródło

https://github.com/ssstonebraker/braker-scripts/blob/master/working-scripts/add_current_shell_and_path_to_crontab.sh

Przykładowe wyjście

add_curent_shell_and_path_to_crontab.sh przykładowe dane wyjściowe

brakertech
źródło
3

Na moim cronie AIX pobiera swoje zmienne środowiskowe z / etc / environment ignorując to, co jest ustawione w .profile.

Edycja: Sprawdziłem również kilka skrzynek Linuksa w różnym wieku i wydaje się, że również mają ten plik, więc prawdopodobnie nie jest to specyficzne dla systemu AIX.

Sprawdziłem to za pomocą sugestii crona Joemallera i sprawdzając dane wyjściowe przed i po edycji zmiennej PATH w / etc / environment.

Van Amburg
źródło
3

Jeśli nie chcesz wprowadzać tych samych zmian w różnych miejscach, z grubsza zrób to:

* * * * * . /home/username/.bashrc && yourcommand all of your args

Plik. space, a następnie ścieżka do .bashrc i polecenie && są magiczne, aby wprowadzić zmiany środowiska do działającej powłoki bash. Również, jeśli naprawdę chcesz, aby powłoka była bash, dobrym pomysłem jest posiadanie linii w swoim pliku crontab:

SHELL=/bin/bash

Mam nadzieję, że to komuś pomoże!

Wade Chandler
źródło
2

Domyślne środowisko dla zadań crona jest bardzo rzadkie i może bardzo różnić się od środowiska, w którym tworzysz swoje skrypty Pythona. W przypadku skryptu, który może być uruchamiany w cronie, każde środowisko, od którego jesteś zależny, powinno być jawnie ustawione. W samym pliku cron dołącz pełne ścieżki do plików wykonywalnych języka Python i skryptów języka Python.

tłum
źródło
2

Wiem, że już na to odpowiedziano, ale pomyślałem, że dla niektórych przyda się. Miałem podobny problem, który niedawno rozwiązałem ( znalazłem tutaj ), a oto najważniejsze kroki, które podjąłem, aby odpowiedzieć na to pytanie:

  1. upewnij się, że masz potrzebne zmienne w PYTHONPATH (znalezione tutaj i tutaj oraz po więcej informacji tutaj) wewnątrz .profile lub .bash_profile dla dowolnej powłoki, w której chcesz przetestować swój skrypt, aby upewnić się, że działa.

  2. edytuj swoją tabelę crontab, aby uwzględnić katalogi potrzebne do uruchomienia skryptu w zadaniu cron (znalezione tutaj i tutaj)

    a) pamiętaj, aby uwzględnić katalog główny w zmiennej PATH (.), jak wyjaśniono tutaj (w zasadzie, jeśli uruchamiasz plik wykonywalny za pomocą polecenia, musi on być w stanie znaleźć root lub katalog, w którym plik wykonywalny jest przechowywany) i prawdopodobnie te (/ sbin: / bin: / usr / sbin: / usr / bin)

  3. w swoim pliku crontab utwórz cronjob, który zmieni katalog na katalog, w którym pomyślnie uruchomiłeś skrypt wcześniej (np. Users / user / Documents / foo)

    a) Będzie to wyglądać następująco:

    * * * * cd /Users/user/Documents/foo; bar -l doSomething -v 
    
śmieszna
źródło
2

@ Trevino: Twoja odpowiedź pomogła mi rozwiązać problem. Jednak dla początkującego, próbując podać podejście krok po kroku.

  1. Pobierz aktualną instalację javy za pośrednictwem $ echo $JAVA_HOME
  2. $ crontab -e
  3. * * * * * echo $PATH- pozwala to zrozumieć, jaka wartość PATH jest obecnie używana przez crontab. Uruchom crontab i pobierz wartość $ PATH używaną przez crontab.
  4. Teraz edytuj ponownie crontab, aby ustawić żądaną ścieżkę bin java: a) crontab -e; b) PATH=<value of $JAVA_HOME>/bin:/usr/bin:/bin(to przykładowa ścieżka); c) teraz twoje zaplanowane zadanie / skrypt jak */10 * * * * sh runMyJob.sh &; d) usuń echo $PATHz pliku crontab, ponieważ nie jest teraz potrzebny.
Ram Dwivedi
źródło
2

Ustaw wymaganą ŚCIEŻKĘ w swoim cronie

crontab -e

Edycja: naciśnij i

PATH=/usr/local/bin:/usr/local/:or_whatever

10 * * * * your_command

Zapisz i wyjdź :wq

Yogesh Yadav
źródło
1

Najprostsze obejście, jakie znalazłem, wygląda następująco:

* * * * * root su -l -c command

Ten przykład wywołuje sujako użytkownik root i uruchamia powłokę z pełnym środowiskiem użytkownika, w tym $ PATH, ustawionym tak, jakby był zalogowany. Działa tak samo na różnych dystrybucjach, jest bardziej niezawodne niż sourcing .bashrc (który nie działa me) i unika zakodowania określonych ścieżek, co może być problemem, jeśli podajesz przykład lub narzędzie konfiguracyjne i nie wiesz, jaka dystrybucja lub układ plików w systemie użytkownika.

Możesz również podać nazwę użytkownika po, sujeśli chcesz mieć innego użytkownika niż root, ale prawdopodobnie powinieneś zostawić rootparametr przed supoleceniem, ponieważ zapewnia suto wystarczające uprawnienia do przełączenia się na dowolnego określonego użytkownika.


źródło
-3

Jeśli powinieneś użyć, webminoto kroki, jak ustawić PATHwartość:

System
  -> Scheduled Cron Jobs
       -> Create a new environment variable
            -> For user: <Select the user name>
            -> Variable name: PATH
            -> Value: /usr/bin:/bin:<your personal path>
            -> Add environment variable: Before all Cron jobs for user
Peter VARGA
źródło