305

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825

10 Answers10

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'])
Daniel Rikowski
  • 71,375
  • 57
  • 251
  • 329
Brian
  • 116,865
  • 28
  • 107
  • 112
  • 94
    It is much simpler to use raw string in windows: r"C:\Temp\a b c\Notepad.exe" – PierreBdR Oct 15 '08 at 09:11
  • 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... – Matthew Scharley Oct 15 '08 at 09:27
  • 1
    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. – Brian Oct 15 '08 at 11:14
  • 1
    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. – Brian Oct 15 '08 at 11:16
  • 6
    @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)) – Brian Oct 15 '08 at 13:11
  • *Yes, the os.exec* functions will replace the current process* - not on Windows; see http://bugs.python.org/issue9148#msg109179 – Piotr Dobrogost Aug 04 '13 at 14:04
  • I tried the same solution but I am getting OSERRoR: Permission denied – Pratik Singhal Oct 07 '13 at 07:52
  • 8
    For python >= 3.5 `subprocess.call` should be replaced by `subprocess.run` https://docs.python.org/3/library/subprocess.html#older-high-level-api – gbonetti Jan 22 '18 at 10:40
90

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user16738
  • 1,223
  • 8
  • 10
  • 1
    Is there an equivalent function for *nix systems? – Unicorn Jun 11 '12 at 15:31
  • @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'."*](http://stackoverflow.com/a/13078786/4279) – jfs Nov 16 '12 at 15:50
36

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

PyGuy
  • 49
  • 3
Daniel Serodio
  • 501
  • 5
  • 4
  • 1
    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. – Zach Young Dec 06 '13 at 21:22
  • 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. – Ethan Furman Nov 12 '14 at 14:11
  • 2
    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()`. – thdoan Dec 30 '14 at 04:09
  • 2
    Don't forget `import os` – Besi Sep 09 '15 at 08:33
20

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)
David Ferenczy Rogožan
  • 23,966
  • 9
  • 79
  • 68
Paul Hoffman
  • 1,820
  • 3
  • 15
  • 20
  • 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. – Tomasz Gandor Sep 28 '16 at 14:23
16

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'])
gbonetti
  • 1,334
  • 17
  • 18
11
import win32api # if active state python is installed or install pywin32 package seperately

try: win32api.WinExec('NOTEPAD.exe') # Works seamlessly
except: pass
sarnold
  • 102,305
  • 22
  • 181
  • 238
rahul
  • 127
  • 1
  • 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. – Tim Richardson Jul 26 '12 at 11:29
  • @rahul and does it except arguments for the executable? So if you want Notepad to open a file or is that seperate? – sayth Jul 30 '12 at 03:40
4

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")
MrValdez
  • 8,515
  • 10
  • 56
  • 79
Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
  • sorry, that does not work either, edited question to reflect this. – Lasse V. Karlsen Oct 15 '08 at 08:29
  • 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. – Brian Oct 15 '08 at 08:39
  • I thought it took both, but you're probably right. I know it works (in the shell atleast) with double quotes. – Matthew Scharley Oct 15 '08 at 09:18
  • +1 this is the best one, windows XP, 2007 home edition worked nicely –  Jul 16 '12 at 12:16
1

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'])
WestAce
  • 860
  • 3
  • 9
  • 23
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
Benyamin Jafari
  • 27,880
  • 26
  • 135
  • 150
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)
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
rajat prakash
  • 189
  • 1
  • 6