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)