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

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

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

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

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

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

РЕДАКТИРОВАТЬ:

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

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

5 ответов

Решение

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

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

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

import os

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

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

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

os.chdir(sys.path[0])

С http://docs.python.org/library/sys.html

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

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

Ваши сценарии и ваши данные не должны быть объединены в один большой каталог. Поместите код в известное место (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 )

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

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

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

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

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

На всякий случай вы также можете использоватьpathlib

      import os
from pathlib import Path

file = Path(__file__)
parent = file.parent
os.chdir(parent)
# print(file, parent, os.getcwd())

Или в одну строку:

      os.chdir(Path(__file__).parent)
Другие вопросы по тегам