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, если каталог недоступен.
Хотя другие решения могут быть более элегантными в конечном итоге для ваших конкретных скриптов, мой пример может быть полезен в тех случаях, когда вы не можете изменить программу или команду, которые вы хотите выполнить.