Je lance un shell python depuis crontab toutes les minutes:
* * * * * /home/udi/foo/bar.py
/home/udi/foo
a quelques sous-répertoires nécessaires, comme /home/udi/foo/log
et /home/udi/foo/config
, qui /home/udi/foo/bar.py
fait référence à.
Le problème est que crontab
le script exécute à partir d'un répertoire de travail différent, donc essayer d'ouvrir ./log/bar.log
échoue.
Existe-t-il une bonne façon de dire au script de changer le répertoire de travail vers le propre répertoire du script? J'aurais envie d'une solution qui fonctionnerait pour n'importe quel emplacement de script, plutôt que d'indiquer explicitement au script où il se trouve.
ÉDITER:
os.chdir(os.path.dirname(sys.argv[0]))
C'était la solution élégante la plus compacte. Merci pour vos réponses et explications!
python
working-directory
Adam Matan
la source
la source
crontab
cas d' utilisation: les deuxsys.argv[0]
et__file__
échouent si le script est exécuté en utilisantexecfile()
;inspect
une solution à base de données pourrait être utilisée à la place.Réponses:
Cela changera votre répertoire de travail actuel en afin que l'ouverture des chemins relatifs fonctionne:
Cependant, vous avez demandé comment changer dans le répertoire de votre script Python, même si vous ne savez pas quel répertoire ce sera lorsque vous écrivez votre script. Pour ce faire, vous pouvez utiliser les
os.path
fonctions:Cela prend le nom de fichier de votre script, le convertit en chemin absolu, puis extrait le répertoire de ce chemin, puis se change dans ce répertoire.
la source
__file__
place desys.argv[0]
.os.chdir(os.path.dirname(__file__))
?__file__
échoue dans les programmes "gelés" (créés à l'aide de py2exe, PyInstaller, cx_Freeze).sys.argv[0]
travaux. @ChrisDown: Si vous souhaitez suivre les liens symboliques;os.path.realpath()
peut être utilisé.__file__
n'est pas déjà un chemin absolu et que l'utilisateur a changé le répertoire de travail, alorsos.path.abspath
échouera de toute façon.Vous pouvez obtenir une version plus courte en utilisant
sys.path[0]
.Depuis http://docs.python.org/library/sys.html#sys.path
la source
Ne fais pas ça.
Vos scripts et vos données ne doivent pas être écrasés dans un seul grand répertoire. Mettez votre code dans un emplacement connu (
site-packages
ou/var/opt/udi
ou quelque chose) séparé de vos données. Utilisez un bon contrôle de version sur votre code pour vous assurer que les versions actuelle et précédente sont séparées les unes des autres afin de pouvoir revenir aux versions précédentes et tester les versions futures.Conclusion: ne mélangez pas le code et les données.
Les données sont précieuses. Le code va et vient.
Fournissez le répertoire de travail comme valeur d'argument de ligne de commande. Vous pouvez fournir une valeur par défaut comme variable d'environnement. Ne le déduisez pas (ou ne le devinez pas)
Faites-en une valeur d'argument obligatoire et faites-le.
N'assumez pas un répertoire basé sur l'emplacement de votre logiciel. Cela ne fonctionnera pas bien à long terme.
la source
Changez votre commande crontab en
Le
(...)
démarre un sous-shell que votre crond exécute en une seule commande. Le|| exit 1
provoque l'échec de votre tâche cron au cas où le répertoire ne serait pas disponible.Bien que les autres solutions puissent être plus élégantes à long terme pour vos scripts spécifiques, mon exemple pourrait toujours être utile dans les cas où vous ne pouvez pas modifier le programme ou la commande que vous souhaitez exécuter.
la source
|| exit 1
. C'est rafraîchissant de voir ça. Bien que jecd /home/udi/foo/ && ./bar.py
exit 1
votre crond sera informé d'une erreur et, dans la plupart des cas, enverra une notification par e-mail de l'échec.