python : 스크립트 작업 디렉토리를 스크립트 자체 디렉토리로 변경하십시오.


171

매분마다 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]))

가장 컴팩트하고 우아한 솔루션이었습니다. 답변과 설명에 감사드립니다!


관련이없는 crontab사용 사례 : 모두 sys.argv[0]__file__스크립트를 사용하여 실행하면 실패 execfile(); 대신 inspect기반 솔루션 을 사용할 수 있습니다.
jfs

답변:


206

상대 경로를 여는 것이 작동하도록 현재 작업 디렉토리가 변경됩니다.

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)

스크립트의 파일 이름을 가져 와서 절대 경로로 변환 한 다음 해당 경로의 디렉토리를 추출한 다음 해당 디렉토리로 변경합니다.


3
디렉토리를 하드 코딩합니다.
Ikke September

2
심볼릭 링크에서 실행하면 작동하지 않습니다. __file__대신에 사용하십시오 sys.argv[0].
Chris Down

1
왜 공감 단계? 왜 간단하지 os.chdir(os.path.dirname(__file__))않습니까?
대령 패닉

8
__file__"frozen"프로그램에서 실패합니다 (py2exe, PyInstaller, cx_Freeze를 사용하여 생성). sys.argv[0]공장. @ChrisDown : 심볼릭 링크를 따르고 싶다면; os.path.realpath()사용 될수있다.
jfs

3
@EliCourtwright __file__아직 절대 경로가 아니고 사용자가 작업 디렉토리를 변경 한 os.path.abspath경우 어쨌든 실패합니다.
Arthur Tacca

45

을 사용하여 더 짧은 버전을 얻을 수 있습니다 sys.path[0].

os.chdir(sys.path[0])

에서 http://docs.python.org/library/sys.html#sys.path

프로그램 시작시 초기화 된이 목록의 첫 번째 항목은 path[0]Python 인터프리터를 호출하는 데 사용 된 스크립트가 포함 된 디렉토리입니다.


23

이러지 마

스크립트와 데이터를 하나의 큰 디렉토리에 으깨서는 안됩니다. 일부 알려진 위치 (에 코드를 삽입 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 )

소프트웨어의 위치에 따라 디렉토리를 "가정"하지 마십시오. 장기적으로는 제대로 작동하지 않습니다.


9
큰 소프트웨어 패키지의 코드와 데이터를 분리하는 것이 옳다고 생각하지만 작은 유지 보수 스크립트에서는 상당히 많이 사용됩니다. 버전 관리에 전적으로 동의합니다.
Adam Matan

3
로트가 맞습니다. 데이터가 일시적인 것이 아닌 한 항상 데이터와 코드를 분리하여 보관하십시오. 예를 들어, 아이콘이있는 경우, 그 데이터이지만, 그것은 일시적인하지, 그리고이 소프트웨어 번들 (그것이 의미하는 것은 무엇이나)에이 상대적으로 고려하는 것이 합리적
스테파노 Borini

5
@Udi Pasmon : 전혀 가져 오지 않았습니다. 조직이 심각한 문제에 빠지게하는 "소규모 유지 관리 스크립트"입니다. 몇 년이 지난 지금이 ​​"작은 유지 보수 스크립트"와 그 데이터는 어린이와 파생물 및 데이터 파일이 풀리고 다시 구현하는 데 악몽이 될 것입니다. 데이터를 가능한 한 코드와 멀리 유지하고 모든 매개 변수를 전달하십시오.
S.Lott

1
+1 OP로하고 싶다고 생각했지만 조언을 읽은 후 대신 스크립트를 수정했습니다. 이제 로그 파일의 위치를 ​​지정하는 매개 변수가 필요합니다.
Iain Samuel McLean 장로

+1. 데이터 디렉토리를 쉽게 사용자 정의 할 수 있으면 Python 스크립트 용 패키지 (rpm)를 작성하는 것이 더 쉽습니다.
jfs

18

crontab 명령을 다음으로 변경하십시오.

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

(...)크론이 단일 명령으로 실행하는 하위 쉘을 시작합니다. 는 || exit 1디렉토리를 사용할 수없는 경우에 실패하여 cronjob에 발생합니다.

다른 스크립트는 특정 스크립트에 대해 장기적으로 더 우아 할 수 있지만 실행하려는 프로그램이나 명령을 수정할 수없는 경우에도 여전히 예제가 유용 할 수 있습니다.


1
이것은 매우 건전한 솔루션입니다. 나는 보통 다른 사람들의 답변을 편집하여 || exit 1. 이것을보고 상쾌합니다. 난 왜 당신이하지 않을 궁금 궁금해cd /home/udi/foo/ && ./bar.py
브루노 Bronosky

2
@BrunoBronosky 명시 적으로 exit 1오류에 대한 알림 메시지가 표시되며 대부분의 경우 실패에 대한 전자 메일 알림을 보냅니다.
Ruud Althuizen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.