I have a simple Python script:
log("Running command: " + str(cmd))
process = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
stdin=subprocess.PIPE, close_fds=close_fds)
I'm executing it on Windows on the same python version 2.6.1, but on different VMs. One is Windows Server 2008 Enterprise, the second one it Windows Server Enterprise and I got error on only one of them.
The log from Windows Server Enterprise:
Running command: C:\Program File\MyProgram\program.exe "parameters"
Error: 'C:\\Program' is not recognized as an internal or external command
The log from Windows Server 2008 Enterprise:
Running command: C:\Program File\MyProgram\program.exe "parameters"
...
The error happens only for one environment. I know that the path should be escaped, but how is that possible that the subprocess.Popen
could handle the path with space and without escaping?
The subprocess module defines one class, Popen and a few wrapper functions that use that class. The constructor for Popen takes arguments to set up the new process so the parent can communicate with it via pipes. It provides all of the functionality of the other modules and functions it replaces, and more.
The main difference is that subprocess. run() executes a command and waits for it to finish, while with subprocess. Popen you can continue doing your stuff while the process finishes and then just repeatedly call Popen.
Popen is nonblocking. call and check_call are blocking. You can make the Popen instance block by calling its wait or communicate method.
subprocess-shell-true | Semgrep. Found 'subprocess' function '$FUNC' with 'shell=True'. This is dangerous because this call will spawn the command using a shell process. Doing so propagates current shell settings and variables, which makes it much easier for a malicious actor to execute commands.
Paths with spaces need to be escaped. The easiest way to do this is to setup the command as a list, add shell=True and let python do the escaping for you:
import subprocess
cmd = [r"C:\Program File\MyProgram\program.exe", "param1", "param2"]
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,stdin=subprocess.PIPE, close_fds=close_fds)
For anybody that stumbles upon this post looking for a solution to this, encapsulating the executable in quotes works on Windows and replacing ' ' with '\ ' works in bash (Linux/MacOS) for Popen shell commands.
Here's what worked for me:
from subprocess import Popen
cmd = '/path/to/some executable with spaces'
# Execute in Windows shell:
Popen(r'"{}"'.format(cmd), shell=True)
# Execute in bash shell:
Popen(cmd.replace(' ', '\ '), shell=True)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With