问题:python:将脚本工作目录更改为脚本自己的目录
我每分钟从crontab运行python shell:
* * * * * /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]))
是最紧凑的优雅解决方案。感谢您的回答和解释!
I run a python shell from crontab every minute:
* * * * * /home/udi/foo/bar.py
/home/udi/foo
has some necessary subdirectories, like /home/udi/foo/log
and /home/udi/foo/config
, which /home/udi/foo/bar.py
refers to.
The problem is that crontab
runs the script from a different working directory, so trying to open ./log/bar.log
fails.
Is there a nice way to tell the script to change the working directory to the script’s own directory? I would fancy a solution that would work for any script location, rather than explicitly telling the script where it is.
EDIT:
os.chdir(os.path.dirname(sys.argv[0]))
Was the most compact elegant solution. Thanks for your answers and explanations!
回答 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)
这将获取脚本的文件名,将其转换为绝对路径,然后提取该路径的目录,然后更改为该目录。
This will change your current working directory to so that opening relative paths will work:
import os
os.chdir("/home/udi/foo")
However, you asked how to change into whatever directory your Python script is located, even if you don’t know what directory that will be when you’re writing your script. To do this, you can use the os.path
functions:
import os
abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)
This takes the filename of your script, converts it to an absolute path, then extracts the directory of that path, then changes into that directory.
回答 1
You can get a shorter version by using sys.path[0]
.
os.chdir(sys.path[0])
From http://docs.python.org/library/sys.html#sys.path
As initialized upon program startup, the first item of this list,
path[0]
, is the directory containing the script that was used to
invoke the Python interpreter
回答 2
不要这样
您的脚本和数据不应混入一个大目录中。把你的代码在一些已知的位置(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 )
不要根据软件的位置“假定”目录。从长远来看,它将无法很好地工作。
Don’t do this.
Your scripts and your data should not be mashed into one big directory. Put your code in some known location (site-packages
or /var/opt/udi
or something) separate from your data. Use good version control on your code to be sure that you have current and previous versions separated from each other so you can fall back to previous versions and test future versions.
Bottom line: Do not mingle code and data.
Data is precious. Code comes and goes.
Provide the working directory as a command-line argument value. You can provide a default as an environment variable. Don’t deduce it (or guess at it)
Make it a required argument value and do this.
import sys
import os
working= os.environ.get("WORKING_DIRECTORY","/some/default")
if len(sys.argv) > 1: working = sys.argv[1]
os.chdir( working )
Do not “assume” a directory based on the location of your software. It will not work out well in the long run.
回答 3
将您的crontab命令更改为
* * * * * (cd /home/udi/foo/ || exit 1; ./bar.py)
在(...)
您的crond执行作为一个单一的命令启动一个子shell。如果|| exit 1
目录不可用,则导致您的cronjob失败。
尽管从长远来看,其他解决方案对于您的特定脚本可能更优雅,但是在您无法修改要执行的程序或命令的情况下,我的示例仍然有用。
Change your crontab command to
* * * * * (cd /home/udi/foo/ || exit 1; ./bar.py)
The (...)
starts a sub-shell that your crond executes as a single command. The || exit 1
causes your cronjob to fail in case that the directory is unavailable.
Though the other solutions may be more elegant in the long run for your specific scripts, my example could still be useful in cases where you can’t modify the program or command that you want to execute.