How do I execute a program from Python? os.system fails due to spaces in path [duplicate]
Asked Answered
C

10

307

I have a Python script that needs to execute an external program, but for some reason fails.

If I have the following script:

import os;
os.system("C:\\Temp\\a b c\\Notepad.exe");
raw_input();

Then it fails with the following error:

'C:\Temp\a' is not recognized as an internal or external command, operable program or batch file.

If I escape the program with quotes:

import os;
os.system('"C:\\Temp\\a b c\\Notepad.exe"');
raw_input();

Then it works. However, if I add a parameter, it stops working again:

import os;
os.system('"C:\\Temp\\a b c\\Notepad.exe" "C:\\test.txt"');
raw_input();

What is the right way to execute a program and wait for it to complete? I do not need to read output from it, as it is a visual program that does a job and then just exits, but I need to wait for it to complete.

Also note, moving the program to a non-spaced path is not an option either.


This does not work either:

import os;
os.system("'C:\\Temp\\a b c\\Notepad.exe'");
raw_input();

Note the swapped single/double quotes.

With or without a parameter to Notepad here, it fails with the error message

The filename, directory name, or volume label syntax is incorrect.

Chlorobenzene answered 15/10, 2008 at 8:24 Comment(0)
L
321

subprocess.call will avoid problems with having to deal with quoting conventions of various shells. It accepts a list, rather than a string, so arguments are more easily delimited. i.e.

import subprocess
subprocess.call(['C:\\Temp\\a b c\\Notepad.exe', 'C:\\test.txt'])
Lux answered 15/10, 2008 at 8:37 Comment(8)
It is much simpler to use raw string in windows: r"C:\Temp\a b c\Notepad.exe"Masjid
Another option may or may not be to use the exec* functions which are also in sys from memory. They take an array in a similar fashion, but I don't think they ever return. Not sure about the semantics here, I recall it mentioned overwriting the current process though, so...Blearyeyed
Yes, the os.exec* functions will replace the current process, so your python process won't continue. They're used more on unix where the general method for a shell to launch a command is to fork() and then exec() in the child.Lux
The windows method for this is the os.spawn family, which could be used instead. subprocess is more portable though, and offers more flexibility in controlling the process (capturing input/output etc), so is preferred.Lux
@PierreBdr: There is a case where rawstrings won't work: where you need a trailing slash. eg r'c:\foo\bar\'. Actually, its probably better to use forward slashes instead. These are accepted throughout the windows API (though not always by some shell commands (eg copy))Lux
Yes, the os.exec functions will replace the current process* - not on Windows; see bugs.python.org/issue9148#msg109179Twoway
I tried the same solution but I am getting OSERRoR: Permission deniedGinseng
For python >= 3.5 subprocess.call should be replaced by subprocess.run docs.python.org/3/library/subprocess.html#older-high-level-apiPrintmaker
L
91

Here's a different way of doing it.

If you're using Windows the following acts like double-clicking the file in Explorer, or giving the file name as an argument to the DOS "start" command: the file is opened with whatever application (if any) its extension is associated with.

filepath = 'textfile.txt'
import os
os.startfile(filepath)

Example:

import os
os.startfile('textfile.txt')

This will open textfile.txt with Notepad if Notepad is associated with .txt files.

Lanctot answered 15/10, 2008 at 20:9 Comment(2)
Is there an equivalent function for *nix systems?Impolitic
@Romeno: you could try: webbrowser.open("textfile.txt") it should open a text editor. See also "start the second program wholly on its own, as though I just 'double-clicked on it'."Cabrilla
M
37

The outermost quotes are consumed by Python itself, and the Windows shell doesn't see it. As mentioned above, Windows only understands double-quotes. Python will convert forward-slashed to backslashes on Windows, so you can use

os.system('"C://Temp/a b c/Notepad.exe"')

The ' is consumed by Python, which then passes "C://Temp/a b c/Notepad.exe" (as a Windows path, no double-backslashes needed) to CMD.EXE

Moynihan answered 26/5, 2009 at 18:13 Comment(4)
This seems the best in a scenario like os.system('curl URL > file') where I want to see cURL's progress meter refresh for really big files.Maynard
If the first letter after a backslash has special meaning (i.e. \t, \n, etc.) then that particular backslash must be doubled. Being a Windows path has nothing to do with it.Subternatural
Note that if you use os.system() on Windows the cmd window will open and remain open until you close the process that it started. IMHO it's better to use os.startfile().Embellish
Don't forget import osXray
I
21

At least in Windows 7 and Python 3.1, os.system in Windows wants the command line double-quoted if there are spaces in path to the command. For example:

  TheCommand = '\"\"C:\\Temp\\a b c\\Notepad.exe\"\"'
  os.system(TheCommand)

A real-world example that was stumping me was cloning a drive in VirtualBox. The subprocess.call solution above didn't work because of some access rights issue, but when I double-quoted the command, os.system became happy:

  TheCommand = '\"\"C:\\Program Files\\Sun\\VirtualBox\\VBoxManage.exe\" ' \
                 + ' clonehd \"' + OrigFile + '\" \"' + NewFile + '\"\"'
  os.system(TheCommand)
Imputation answered 26/10, 2009 at 1:33 Comment(1)
That was it! I'd go for subprocess, but sometimes os.system and os.popen(...).read() are just faster to type. BTW, you don't need to escape double quotes inside single, i.e. '""C:\\Temp\\a b c\\Notepad.exe""' will do.Cholesterol
P
17

For python >= 3.5 subprocess.run should be used in place of subprocess.call

https://docs.python.org/3/library/subprocess.html#older-high-level-api

import subprocess
subprocess.run(['notepad.exe', 'test.txt'])
Printmaker answered 22/1, 2018 at 13:16 Comment(0)
U
12
import win32api # if active state python is installed or install pywin32 package seperately

try: win32api.WinExec('NOTEPAD.exe') # Works seamlessly
except: pass
Unlikely answered 30/4, 2010 at 7:8 Comment(2)
and it seems no quoting is needed with this method, eg win32api.WinExec('pythonw.exe d:\web2py\web2py.py -K welcome') starts the web2py scheduler in the background.Ed
@Unlikely and does it except arguments for the executable? So if you want Notepad to open a file or is that seperate?Cinque
B
5

I suspect it's the same problem as when you use shortcuts in Windows... Try this:

import os
os.system("\"C:\\Temp\\a b c\\Notepad.exe\" C:\\test.txt")
Blearyeyed answered 15/10, 2008 at 8:27 Comment(4)
sorry, that does not work either, edited question to reflect this.Chlorobenzene
I think windows only uses ", rather than ' for quoting. This will probably work if you change this. However you'll still run into problems with if you have embedded quotes etc.Lux
I thought it took both, but you're probably right. I know it works (in the shell atleast) with double quotes.Blearyeyed
+1 this is the best one, windows XP, 2007 home edition worked nicelyRectocele
C
2

For Python 3.7, use subprocess.call. Use raw string to simplify the Windows paths:

import subprocess
subprocess.call([r'C:\Temp\Example\Notepad.exe', 'C:\test.txt'])
Country answered 7/8, 2019 at 16:55 Comment(0)
P
0

Suppose we want to run your Django web server (in Linux) that there is space between your path (path='/home/<you>/<first-path-section> <second-path-section>'), so do the following:

import subprocess

args = ['{}/manage.py'.format('/home/<you>/<first-path-section> <second-path-section>'), 'runserver']
res = subprocess.Popen(args, stdout=subprocess.PIPE)
output, error_ = res.communicate()

if not error_:
    print(output)
else:
    print(error_)

[Note]:

  • Do not forget accessing permission: chmod 755 -R <'yor path'>
  • manage.py is exceutable: chmod +x manage.py
Perea answered 22/1, 2018 at 13:29 Comment(0)
K
0

No need for sub-process, It can be simply achieved by

GitPath="C:\\Program Files\\Git\\git-bash.exe"# Application File Path in mycase its GITBASH
os.startfile(GitPath)
Kuster answered 26/4, 2020 at 4:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.