2

I am trying to execute a shell command, for e.g "ls" in a different directory from my python script. I am having issues changing the directory directly from the python code from subprocess.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 1
    What do you want to achieve can you please post some example code of what you have tried? – Krk Rama Krishna Sep 27 '20 at 08:11
  • Does this answer your question? [Python: Subprocess "call" function can't find path](https://stackoverflow.com/questions/38231176/python-subprocess-call-function-cant-find-path) – woblob Sep 27 '20 at 08:18

2 Answers2

2

The subprocess methods all accept a cwd keyword argument.

import subprocess

d = subprocess.check_output(
    ['ls'], cwd='/home/you/Desktop')

Obviously, replace /home/you/Desktop with the actual directory you want.

Most well-written shell commands will not require you to run them in any particular directory, but if that's what you want, this is how you do it.

If this doesn't solve your problem, please update your question to include the actual code which doesn't behave like you expect.

(Of course, a subprocess is a really poor way to get a directory listing, and ls is a really poor way to get a directory listing if you really want to use a subprocess. Probably try os.listdir('/home/you/Desktop') if that's what you actually want. But I'm guessing you are just providing ls as an example of an external command.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Okay, to be more particular i am building a GUI in python. In the GUI i am connecting a button to a function which runs the shell command "make check" for a particular make file in a different directory. The point here is that the directory where the makefile is located is not fixed(can be anywhere in the system), so at first i am extracting the location of the directory and adding it to the variable. I still have to try the cwd command but i hope it works or is there any other easy and more efficient way to do it. Also "ls" was just an example, definitely not listing contents with subprocess. – dhruvguptadg Sep 27 '20 at 21:41
  • `make -C directory check` should work too. That is, `subprocess.run(['make', '-C', directory, 'check'])` where we assume `directory` is a variable which contains the path to the directory. – tripleee Sep 28 '20 at 07:32
  • Perhaps tangentially see also [What exactly is current working directory?](https://stackoverflow.com/questions/45591428/what-exactly-is-current-working-directory) – tripleee Nov 10 '21 at 11:46
2

To add to tripleees excellent answer, you can solve this in 3 ways:

  1. Use subprocess' cwd argument
  2. Change dir before, using os.chdir
  3. Run the shell command to the exact dir you want, e.g. ls /path/to/dir OR cd /path/to/dir; ls, but note that some shell directives (e.g. &&, ;) cannot be used without adding shell=True to the method call

PS as tripleee commented, using shell=True is not encouraged and there are a lot of things that should be taken into consideration when using it

CIsForCookies
  • 12,097
  • 11
  • 59
  • 124
  • 1
    `;` is among those, too. You really want to avoid `shell=True` if you can; see [Actual meaning of `shell=True` in `subprocess`](https://stackoverflow.com/questions/3172470/actual-meaning-of-shell-true-in-subprocess) – tripleee Sep 27 '20 at 09:27
  • I agree shell=True is less than ideal. I only want to show here the range of possibilities. I actually ordered it from best to worst, however, some cases can benefit from it – CIsForCookies Sep 27 '20 at 09:31
  • Sure, it's just that you gloss over the complications. With `shell=True` you normally pass in a single string and let the shell parse it, so e.g. `ls /home/you/Desktop` will work fine. Without `shell=True` you need to split this into a list yourself; `['ls', '/home/you/Desktop']` – tripleee Sep 27 '20 at 09:35
  • I always pass the string like `ls bla bla`. When adding shell True I leave it as it is, and when it's false, I add split() – CIsForCookies Sep 27 '20 at 09:38
  • Plain `split` doesn't work if your command has quoted strings which contain whitespace. There's `shlex.split()` which can handle this, and other complications; but again, perhaps your answer should spell these things out, or at least note that it's not entirely trivial to summarize the differences. – tripleee Sep 27 '20 at 09:40