Python: изменить рабочий каталог сценариев в собственный каталог script

Я запускаю оболочку python из crontab каждую минуту:

* * * * * /home/udi/foo/bar.py

/home/udi/foo имеет некоторые необходимые подкаталоги, такие как /home/udi/foo/log и /home/udi/foo/config, к которому относится /home/udi/foo/bar.py.

Проблема заключается в том, что crontab запускает script из другого рабочего каталога, поэтому попытка открыть ./log/bar.log завершается с ошибкой.

Есть ли хороший способ сообщить script изменить рабочий каталог в собственный каталог script? Я хотел бы предложить решение, которое будет работать для любого местоположения script, а не явно указывать script, где оно есть.

EDIT:

os.chdir(os.path.dirname(sys.argv[0]))

Было самым компактным изящным решением. Спасибо за ваши ответы и объяснения!

Ответ 1

Это изменит ваш текущий рабочий каталог таким образом, чтобы открытые относительные пути работали:

import os
os.chdir("/home/udi/foo")

Однако вы спросили, как перейти в любой каталог, в котором находится ваш Python script, даже если вы не знаете, какой каталог будет, когда вы пишете script. Для этого вы можете использовать функции os.path:

import os

abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)

Это берет имя файла вашего script, преобразует его в абсолютный путь, затем извлекает каталог этого пути и затем переходит в этот каталог.

Ответ 2

Вы можете получить более короткую версию с помощью sys.path[0].

os.chdir(sys.path[0])

От http://docs.python.org/library/sys.html#sys.path

Как инициализировано при запуске программы, первый элемент этого списка, path[0], это каталог, содержащий script, который использовался для вызывать интерпретатор Python

Ответ 3

Не делайте этого.

Ваши сценарии и ваши данные не должны быть перепутаны в один большой каталог. Поместите свой код в известное местоположение (site-packages или /var/opt/udi или что-то еще), отдельно от ваших данных. Используйте хороший контроль версий на своем коде, чтобы быть уверенным, что у вас есть текущие и предыдущие версии, отделенные друг от друга, чтобы вы могли вернуться к предыдущим версиям и протестировать будущие версии.

Нижняя строка: не смешивайте код и данные.

Данные ценны. Код приходит и уходит.

Предоставить рабочий каталог в качестве значения аргумента командной строки. Вы можете указать значение по умолчанию в качестве переменной среды. Не выводите его (или угадывайте)

Сделайте это обязательным значением аргумента и сделайте это.

import sys
import os
working= os.environ.get("WORKING_DIRECTORY","/some/default")
if len(sys.argv) > 1: working = sys.argv[1]
os.chdir( working )

Не "предполагайте" каталог, основанный на местоположении вашего программного обеспечения. В конечном итоге это не сработает.

Ответ 4

Измените команду crontab на

* * * * * (cd /home/udi/foo/ || exit 1; ./bar.py)

(...) запускает суб-оболочку, которую ваш коронка выполняет как одну команду. || exit 1 приводит к сбою вашего cronjob, если каталог недоступен.

Хотя другие решения могут быть более элегантными в конечном итоге для ваших конкретных скриптов, мой пример может быть полезен в тех случаях, когда вы не можете изменить программу или команду, которые вы хотите выполнить.