Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Python's subprocess.Popen accept spaces in paths?

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?

like image 282
erkfel Avatar asked Sep 03 '14 23:09

erkfel


People also ask

How does subprocess Popen work in Python?

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.

What is the difference between subprocess Popen and run?

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.

Does subprocess Popen block?

Popen is nonblocking. call and check_call are blocking. You can make the Popen instance block by calling its wait or communicate method.

Why are shells true in subprocess?

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.


2 Answers

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)
like image 149
tdelaney Avatar answered Sep 21 '22 00:09

tdelaney


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)
like image 30
Viktor Petrov Avatar answered Sep 21 '22 00:09

Viktor Petrov