85

I'm calling a command line program in python using the os.system(command) call.

How can I call this command passing a different folder for execution? There is a system call for this? Or I should save the current folder, and, after execution, change restore it.

Victor
  • 8,309
  • 14
  • 80
  • 129

3 Answers3

123

The subprocess module is a very good solution.

import subprocess
p = subprocess.Popen([command, argument1,...], cwd=working_directory)
p.wait()

It has also arguments for modifying environment variables, redirecting input/output to the calling program, etc.

craymichael
  • 4,578
  • 1
  • 15
  • 24
hynekcer
  • 14,942
  • 6
  • 61
  • 99
  • 1
    Sometimes it's hard to know how to split your cmd into args. Run `import shlex args = shlex.split('your long command --here with --params')` and it will show you how to break it down. – Peter Dec 01 '22 at 22:34
  • Yes, the function `shlex.split` could be useful if you need to split e.g. arguments with quotes and spaces, but it is still unsafe with an unchecked user input that can contain e.g. backslashes and quotes. It is easy to split a simple command string by a normal `str.split` and combine it with a user input or with a pathname, but it would be unsafe to merge these strings together first and then split then by shlex.split(). – hynekcer Dec 02 '22 at 08:31
28

Try to os.chdir(path) before invoking the command.

From here:

os.chdir(path) Change the current working directory to path.

Availability: Unix, Windows

EDIT

This will change the current working dir, you can get the current working by:

os.getcwd()

If you want to save it and restore it later, if you need to do some work in the original working dir.

EDIT 2

In any case you should probably move to subprocess (doc) as suggested here. If you use subprocess's Popen you have the choice of providing cwd parameter to specify the working directory for the subprocess: read this.

subprocess.Popen(args, bufsize=0, executable=None, stdin=None,
stdout=None, stderr=None, preexec_fn=None, close_fds=False,
shell=False, cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0)

...

If cwd is not None, the child’s current directory will be changed to cwd before it is executed. Note that this directory is not considered when searching the executable, so you can’t specify the program’s path relative to cwd.

zenpoy
  • 19,490
  • 9
  • 60
  • 87
  • 1
    Did you read the question? I know this will work, but it's not a good approach! – Victor Dec 06 '12 at 13:24
  • 2
    @Victor read the edits... if you need `os.system()` that's the only way. if you can consider moving to `subprocess` you have the `cwd` arg – zenpoy Dec 06 '12 at 13:36
4

Here, I made a little function to change the path you're working on :

import os
def make_path(r_path):  
    ack = 1
    try:
        root = os.path.dirname(__file__)
        rel_path = os.path.join("..", r_path)

        abs_path = os.path.join(root, rel_path)
        os.chdir(abs_path)
        ack = 0
    except Exception as details:
        print('problem to get to the path '+r_path+' (0001) : ' + str(details))
    return ack

So here, r_path is the relative path you want to go to. I added ".." to the path.join() methode so, if you're in a folder and want to exit it before searching for your path, it does it automatically. So, if your relative directory looks like this :

-path_to_reach
    -a_random_file.txt
-your_current_folder
    -your_program.py

you can do those lines to go inside the path_to_reach and make your command, in exemple :

command = ls
make_path('path_to_reach/')
os.system(command)

This command would not be useful, but you see the idea!