views:

396

answers:

2

Hi,

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!

+5  A: 

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
from sys import argv

abspath = os.path.abspath(argv[0])
dname = os.path.dirname(abspath)
os.chdir(dname)

This takes the filename of your script, which is always sys.argv[0] and converts it to an absolute path, then extracts the directory of that path, then changes into that directory.

Eli Courtwright
Equals hardcoding the directory.
Ikke
I added info on how to change into the script's directory; I posted a partial answer while I looked up the os.path functions, which I couldn't remember off the top of my head.
Eli Courtwright
+2  A: 

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.

S.Lott
I think you're right about separating code and data for large software packages, but it seems quite far-fetched for a small maintenance script. I totally agree about the version control.
Adam Matan
S. Lott is right. Always keep data and code separated, unless data is not transitory. For example, if you have icons, that is data, but it's not transitory, and it makes sense to consider it relative to the software bundle (whatever that means)
Stefano Borini
@Udi Pasmon: Not far-fetched at all. It's the "small maintenance scripts" that get organizations into deep trouble. Years from now, this "small maintenance script" and it's children and derivations and data files will be a nightmare to disentangle and reimplement. Keep data as far from code as possible -- pass parameters for everything -- assume nothing.
S.Lott