python: Komut dosyaları çalışma dizinini komut dosyasının kendi dizinine değiştirin


171

Her dakika crontab'dan bir python kabuğu çalıştırıyorum:

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

/home/udi/foogibi, bazı gerekli alt dizinleri vardır /home/udi/foo/logve /home/udi/foo/configbu, /home/udi/foo/bar.pyifade eder.

Sorun, crontabkomut dosyasını farklı bir çalışma dizininden çalıştırdığı için açmaya çalışmak ./log/bar.logbaşarısız oluyor.

Betiğe çalışma dizinini betiğin kendi dizinine değiştirmesini söylemenin güzel bir yolu var mı? Ben açıkça komut dosyası nerede olduğunu söylemek yerine, herhangi bir komut dosyası konumu için işe yarayacak bir çözüm fantezi.

DÜZENLE:

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

En kompakt zarif çözümdü. Cevaplarınız ve açıklamalarınız için teşekkürler!


crontabuse-case ile ilgisiz : her ikisi de sys.argv[0]ve __file__script kullanılarak çalıştırılırsa başarısız olur execfile(); inspecttabanlı bir çözüm kullanılabilir.
jfs

Yanıtlar:


206

Bu, geçerli çalışma dizininizi, göreli yolları açmanın çalışacağı şekilde değiştirir:

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

Ancak, komut dosyanızı yazarken hangi dizinin olacağını bilmeseniz bile, Python betiğinizin bulunduğu dizine nasıl geçeceğinizi sordunuz. Bunu yapmak için os.pathişlevleri kullanabilirsiniz :

import os

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

Bu, komut dosyanızın dosya adını alır, mutlak bir yola dönüştürür, sonra bu yolun dizinini çıkarır, sonra bu dizine dönüşür.


3
Dizinin kodlanmasına eşittir.
Ikke

2
Bir sembolik bağlantıdan çalıştırıyorsanız, bu çalışmaz. Yerine __file__kullanın sys.argv[0].
Chris Down

1
Neden abspath adımı? Neden basit değil os.chdir(os.path.dirname(__file__))?
Albay Panik

8
__file__"dondurulmuş" programlarda başarısız olur (py2exe, PyInstaller, cx_Freeze kullanılarak oluşturulmuştur). sys.argv[0]İşler. @ChrisDown: Symlinks'i takip etmek istiyorsanız; os.path.realpath()kullanılabilir.
jfs

3
@EliCourtwright __file__Zaten mutlak bir yol değilse ve kullanıcı çalışma dizinini değiştirdiyse, os.path.abspathyine de başarısız olur.
Arthur Tacca

46

Düğmesini kullanarak daha kısa bir sürüm elde edebilirsiniz sys.path[0].

os.chdir(sys.path[0])

Gönderen http://docs.python.org/library/sys.html#sys.path

Bu listenin ilk öğesi olan program başlangıcında başlatıldığı gibi path[0], Python yorumlayıcısını çağırmak için kullanılan komut dosyasını içeren dizindir


23

Bunu yapma.

Komut dosyalarınız ve verileriniz büyük bir dizinde ezilmemelidir. Bazı bilinen konumunda (kodunuzu koyun site-packagesveya /var/opt/udifalan) Verilerinizden ayırın. Geçerli ve önceki sürümlerin birbirinden ayrıldığından emin olmak için kodunuzda iyi sürüm kontrolü kullanın, böylece önceki sürümlere geri dönebilir ve gelecekteki sürümleri test edebilirsiniz.

Alt satır: Kod ve verileri karıştırmayın.

Veriler değerlidir. Kod gelir ve gider.

Çalışma dizinini komut satırı bağımsız değişken değeri olarak sağlayın. Ortam değişkeni olarak varsayılan bir değer sağlayabilirsiniz. Çıkarım (ya da tahmin et)

Bunu gerekli bir bağımsız değişken değeri yapın ve bunu yapın.

import sys
import os
working= os.environ.get("WORKING_DIRECTORY","/some/default")
if len(sys.argv) > 1: working = sys.argv[1]
os.chdir( working )

Yazılımınızın konumuna göre bir dizin "varsaymayın". Uzun vadede iyi çalışmaz.


9
Büyük yazılım paketleri için kod ve verileri ayırmak konusunda haklı olduğunuzu düşünüyorum, ancak küçük bir bakım komut dosyası için oldukça uzak görünüyor. Sürüm kontrolü konusunda tamamen katılıyorum.
Adam Matan

3
S. Lott haklı. Veriler geçici değilse, verileri ve kodu her zaman ayrı tutun. Örneğin, simgeleriniz varsa, bu veri, ancak geçici değildir ve bunu yazılım paketine göre düşünmek mantıklıdır (ne anlama gelirse)
Stefano Borini

5
@Udi Pasmon: Hiç de zor değil. Organizasyonları büyük sorun haline getiren "küçük bakım senaryoları" dır. Yıllar sonra, bu "küçük bakım betiği" ve onun çocuklar ve türevleri ve veri dosyaları çözmek ve yeniden uygulamak için bir kabus olacak. Verileri koddan mümkün olduğunca uzak tutun - her şey için parametreleri geçirin - hiçbir şey varsaymayın.
S.Lott

1
+1 OP olarak yapmak istediğimi sanıyordum, ama tavsiyeni okuduktan sonra senaryomu değiştirdim. Şimdi bir günlük dosyasının konumunu belirtmek için bir parametre gerektirir.
Iain Samuel McLean Elder

+1. Veri dizinleri kolayca özelleştirilebiliyorsa, bir python betiği için bir paket (rpm) oluşturmak daha kolaydır.
jfs

18

Crontab komutunuzu olarak değiştirin

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

Başlangıçta (...), crond'ınızın tek bir komut olarak yürüttüğü bir alt kabuk başlar. Dizinin || exit 1kullanılamaması durumunda cronjob'ınızın başarısız olmasına neden olur.

Diğer komutlar belirli komut dosyalarınız için uzun vadede daha zarif olsa da, örneğim yürütmek istediğiniz programı veya komutu değiştiremediğiniz durumlarda yine de yararlı olabilir.


1
Bu son derece sağlam bir çözümdür. Kendimi genellikle diğer insanların cevaplarını düzenlerken buluyorum || exit 1. Bunu görmek canlandırıcı. Sadece neden yapmayacağınızı merak etmeme rağmencd /home/udi/foo/ && ./bar.py
Bruno Bronosky

2
@BrunoBronosky Açık olarak exit 1crond'ınıza bir hata bildirilir ve çoğu durumda hataya ilişkin bir e-posta bildirimi gönderilir.
Ruud Althuizen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.