Co minutę uruchamiam powłokę Pythona z crontaba:
* * * * * /home/udi/foo/bar.py
/home/udi/foo
ma pewne niezbędne podkatalogi, takie jak /home/udi/foo/log
i /home/udi/foo/config
, do którego /home/udi/foo/bar.py
odwołuje się.
Problem polega na tym, że crontab
uruchamia skrypt z innego katalogu roboczego, więc próba otwarcia ./log/bar.log
kończy się niepowodzeniem.
Czy istnieje dobry sposób, aby powiedzieć skryptowi, aby zmienił katalog roboczy na własny katalog skryptu? Spodobało mi się rozwiązanie, które działałoby dla dowolnej lokalizacji skryptu, zamiast wyraźnie wskazywać skryptowi, gdzie on się znajduje.
EDYTOWAĆ:
os.chdir(os.path.dirname(sys.argv[0]))
Było najbardziej kompaktowym, eleganckim rozwiązaniem. Dziękuję za odpowiedzi i wyjaśnienia!
python
working-directory
Adam Matan
źródło
źródło
crontab
przypadkiem użycia: obasys.argv[0]
i__file__
kończą się niepowodzeniem, jeśli skrypt jest uruchamiany przy użyciuexecfile()
; Zamiast tego można użyćinspect
rozwiązania opartego na rozwiązaniach .Odpowiedzi:
Spowoduje to zmianę bieżącego katalogu roboczego na tak, aby otwieranie ścieżek względnych działało:
Jednak zapytałeś, jak przejść do dowolnego katalogu, w którym znajduje się skrypt Pythona, nawet jeśli nie wiesz, który to będzie katalog podczas pisania skryptu. Aby to zrobić, możesz użyć
os.path
funkcji:Pobiera nazwę pliku skryptu, konwertuje go na ścieżkę bezwzględną, następnie wyodrębnia katalog z tej ścieżki, a następnie przechodzi do tego katalogu.
źródło
__file__
zamiastsys.argv[0]
.os.chdir(os.path.dirname(__file__))
?__file__
nie działa w „zamrożonych” programach (utworzonych przy użyciu py2exe, PyInstaller, cx_Freeze).sys.argv[0]
Pracuje. @ChrisDown: Jeśli chcesz śledzić linki symboliczne;os.path.realpath()
może być użyty.__file__
nie jest jeszcze ścieżką bezwzględną, a użytkownik zmienił katalog roboczy, ios.path.abspath
tak zakończy się niepowodzeniem.Możesz uzyskać krótszą wersję, używając
sys.path[0]
.Z http://docs.python.org/library/sys.html#sys.path
źródło
Nie rób tego.
Twoje skrypty i dane nie powinny być łączone w jeden duży katalog. Umieścić swój kod w jakiejś znanej lokalizacji (
site-packages
lub/var/opt/udi
czy coś) oddzielone od danych. Używaj dobrej kontroli wersji w swoim kodzie, aby mieć pewność, że masz oddzielone od siebie wersje bieżące i poprzednie, dzięki czemu możesz wrócić do poprzednich wersji i przetestować przyszłe wersje.Konkluzja: nie łącz kodu i danych.
Dane są cenne. Kod przychodzi i odchodzi.
Podaj katalog roboczy jako wartość argumentu wiersza polecenia. Możesz podać wartość domyślną jako zmienną środowiskową. Nie dedukuj tego (ani nie zgaduj)
Ustaw wymaganą wartość argumentu i zrób to.
Nie „zakładaj” katalogu na podstawie lokalizacji oprogramowania. Na dłuższą metę nie będzie dobrze działać.
źródło
Zmień polecenie crontab na
(...)
Rozpoczyna sub-shell, że crond wykonywany jako jednego polecenia.|| exit 1
Powoduje, że cron niepowodzenie w przypadku, że katalog jest niedostępny.Chociaż inne rozwiązania mogą na dłuższą metę być bardziej eleganckie dla określonych skryptów, mój przykład może być nadal przydatny w przypadkach, gdy nie możesz zmodyfikować programu lub polecenia, które chcesz wykonać.
źródło
|| exit 1
. To orzeźwiające widzieć to. Chociaż muszę się zastanawiać, dlaczego po prostu nie zrobiłeścd /home/udi/foo/ && ./bar.py
exit 1
twój crond zostanie powiadomiony o błędzie, aw większości przypadków wyśle e-mail z powiadomieniem o błędzie.