web-dev-qa-db-ja.com

python:スクリプトの作業ディレクトリをスクリプト自身のディレクトリに変更します

Crontabから毎分pythonシェルを実行します:

* * * * * /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]))

最もコンパクトでエレガントなソリューションでした。回答と説明をありがとう!

146
Adam Matan

これにより、現在の作業ディレクトリが変更され、相対パスを開くことができるようになります。

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)

これは、スクリプトのファイル名を取得し、絶対パスに変換し、そのパスのディレクトリを抽出してから、そのディレクトリに変更します。

177
Eli Courtwright

sys.path[0]を使用して短いバージョンを取得できます。

os.chdir(sys.path[0])

http://docs.python.org/library/sys.html#sys.path から

プログラムの起動時に初期化されると、このリストの最初の項目path[0]は、Pythonインタープリターを呼び出すために使用されたスクリプトを含むディレクトリです。

44
xverges

これをしないでください。

スクリプトとデータを1つの大きなディレクトリにマッシュしないでください。データとは別の既知の場所(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 )

ソフトウェアの場所に基づいてディレクトリを「想定」しないでください。長期的にはうまくいきません。

21
S.Lott

Crontabコマンドを次のように変更します

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

(...)は、crondが単一のコマンドとして実行するサブシェルを開始します。 || exit 1を使用すると、ディレクトリが使用できない場合にcronjobが失敗します。

他のソリューションは、特定のスクリプトの長期的にはよりエレガントかもしれませんが、私の例は、実行したいプログラムやコマンドを変更できない場合に役立ちます。

17
Ruud Althuizen