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]))
最もコンパクトでエレガントなソリューションでした。回答と説明をありがとう!
これにより、現在の作業ディレクトリが変更され、相対パスを開くことができるようになります。
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#sys.path から
プログラムの起動時に初期化されると、このリストの最初の項目
path[0]
は、Pythonインタープリターを呼び出すために使用されたスクリプトを含むディレクトリです。
これをしないでください。
スクリプトとデータを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 )
ソフトウェアの場所に基づいてディレクトリを「想定」しないでください。長期的にはうまくいきません。
Crontabコマンドを次のように変更します
* * * * * (cd /home/udi/foo/ || exit 1; ./bar.py)
(...)
は、crondが単一のコマンドとして実行するサブシェルを開始します。 || exit 1
を使用すると、ディレクトリが使用できない場合にcronjobが失敗します。
他のソリューションは、特定のスクリプトの長期的にはよりエレガントかもしれませんが、私の例は、実行したいプログラムやコマンドを変更できない場合に役立ちます。