python: cambie el directorio de trabajo de los scripts al directorio propio del script
-
07-07-2019 - |
Pregunta
Ejecuto un shell de Python desde crontab cada minuto:
* * * * * /home/udi/foo/bar.py
/ home / udi / foo
tiene algunos subdirectorios necesarios, como / home / udi / foo / log
y / home / udi / foo / config
, al que se refiere /home/udi/foo/bar.py
.
El problema es que crontab
ejecuta el script desde un directorio de trabajo diferente, por lo que falla al intentar abrir ./log/bar.log
.
¿Hay una buena manera de decirle al script que cambie el directorio de trabajo al propio directorio del script? Me gustaría una solución que funcionara para cualquier ubicación de script, en lugar de decirle explícitamente al script dónde está.
EDIT:
os.chdir(os.path.dirname(sys.argv[0]))
Fue la solución elegante más compacta. ¡Gracias por sus respuestas y explicaciones!
Solución
Esto cambiará su directorio de trabajo actual para que la apertura de rutas relativas funcione:
import os
os.chdir("/home/udi/foo")
Sin embargo, usted preguntó cómo cambiar a cualquier directorio en el que se encuentre su script Python, incluso si no sabe qué directorio será cuando escriba su script. Para hacer esto, puede usar las funciones os.path
:
import os
abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)
Esto toma el nombre de archivo de su script, lo convierte en una ruta absoluta, luego extrae el directorio de esa ruta, luego cambia a ese directorio.
Otros consejos
Puede obtener una versión más corta utilizando sys.path [0]
.
os.chdir(sys.path[0])
De http://docs.python.org/library/sys.html # sys.path
Como se inicializó al iniciar el programa, el primer elemento de esta lista,
ruta [0]
, es el directorio que contiene el script que se utilizó para invocar al intérprete de Python
No hagas esto.
Sus scripts y sus datos no deben combinarse en un directorio grande. Ponga su código en alguna ubicación conocida ( paquetes de sitio
o / var / opt / udi
o algo) separado de sus datos. Utilice un buen control de versiones en su código para asegurarse de que tiene versiones actuales y anteriores separadas entre sí para que pueda recurrir a versiones anteriores y probar versiones futuras.
Conclusión: no mezcle código y datos.
Los datos son preciosos. El código va y viene.
Proporcione el directorio de trabajo como un valor de argumento de línea de comando. Puede proporcionar un valor predeterminado como variable de entorno. No lo deduzca (ni lo adivine)
Conviértalo en un valor de argumento requerido y haga esto.
import sys
import os
working= os.environ.get("WORKING_DIRECTORY","/some/default")
if len(sys.argv) > 1: working = sys.argv[1]
os.chdir( working )
No "asuma" un directorio basado en la ubicación de su software. No funcionará bien a largo plazo.
Cambie su comando crontab a
* * * * * (cd /home/udi/foo/ || exit 1; ./bar.py)
El (...)
inicia un sub-shell que su crond ejecuta como un solo comando. El
Aunque las otras soluciones pueden ser más elegantes a largo plazo para sus scripts específicos, mi ejemplo aún podría ser útil en los casos en que no pueda modificar el programa o comando que desea ejecutar.