Reputation: 2668
I'd like to execute a simple batch file using Python. But I'm getting some error back from the process saying the file, directory or disc name is not right. I guess the best way to start is to show the code:
import subprocess as sp
from pathlib import Path
file = Path(r'C:\Program Files (x86)\test.bat')
p = sp.Popen(['"' + str(file) + '"'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE,
shell=True, universal_newlines=True)
outs, errs = p.communicate('', timeout=5)
print(outs, '\n-----\n', errs)
I extended this with appending to system path and changing the working directory:
import os
import sys
sys.path.append(file.parent)
os.chdir(file.parent)
The batch file contains just a few echo commands for debugging. So I'd expect the code above to print the contents of the echoes. I've verified that I'm able to call it inside a command prompt from any folder. Previously I was getting some file permission error (WinError 5
), so that might be related especially as the file is in Program Files. This error was not from the process, but Python itself.
I also tried it with an executable, and a similar error was raised: WinError 2: the system cannot find the file specified
. Any idea where I'm stumbling?
shell=True
keyword is removed, the WinError 5
is backPopen
is called with ['cmd']
and the batch file is run with p.communicate('"' + str(file) + '"\n', timeout=5)
, no errors are thrown, and the output contains the echoes. However batch files should run without explicitly opening a command prompt, I presume.Upvotes: 0
Views: 3380
Reputation: 34270
Use a command-line string instead of an args list when passing shell=True
or when running a batch script with the default shell=False
.
On Windows, Popen
processes an args list into a command line that's compatible with VC++ argument parsing. But cmd.exe don't use VC++ argument parsing rules, and even for an executable that does use VC++ rules (e.g. python.exe), the extra quotes you're adding (i.e. '"' + str(file) + '"'
) get backslash-escaped as literal quotation marks in the command line.
Upvotes: 3