why this dos command does not work inside python? - python

I try to move some dos command from my batch file into python but get this error, The filename, directory name, or volume label syntax is incorrect, for the following statement.
subprocess.Popen('rd /s /q .\ProcessControlSimulator\bin', shell=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if I just copy that dos command into window console, it works. The os.getcwd() gave me expected working directory.
My questions are:
1. why is that?
2. how to avoid that? do I need to get current working directory and construct an abstract path for that command? how to do that?
thanks

\ (backslash) is an escape character within string constants, so your string ends up changed. Use double \s (like so \\) within string constants:
subprocess.Popen('rd /s /q .\\ProcessControlSimulator\\bin', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

My advice is try not to use system commands unnecessarily. You are using Python, so use the available modules that come with it. From what i see, you are trying to remove directories right? Then you can use modules like shutil. Example:
import shutil
import os
path = os.path.join("c:\\","ProcessControlSimulator","bin") #example only
try:
shutil.rmtree(path)
except Exception,e:
print e
else:
print "removed"
there are others also, like os.removedirs, os.remove you can take a look at from the docs.

You've got unescaped backslashes. You can use a python raw string to avoid having to escape your slashes, or double them up:
subprocess.Popen(r'rd /s /q .\ProcessControlSimulator\bin', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
or
subprocess.Popen('rd /s /q .\\ProcessControlSimulator\\bin', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

You can't just copy it one-to-one. For example, your escape characters () become incorrect. You may need a double \ in this case.
Also, there are specific API calls for creating and killing directories, look at os.path

Related

Subprocess with a variable that contains a whitespace (path)

Just started Python again and now I'm already stuck on the following...
I'm trying to use subprocess.Popen with a variable with a whitespace in it (a Windows path).
Doing a print on the variable the variable seems to work fine. But when using the variable in subprocess.Popen, the variable is cut off by the first whitespace.
Below a part of the script (the variable 'image_file' contains the Windows Path(s) with spaces)
def start_phone(image_file):
cmd = tar_exe + " -tf "+ image_file
print (cmd)
subprocess.Popen(cmd, shell=True)
How can I use subprocess with a variable with whitespaces (path) in it?
You can either put double quotes around each argument with potential white spaces in it:
cmd = f'"{tar_exe}" -tf "{image_file}"'
subprocess.Popen(cmd, shell=True)
or don't use shell=True and instead put arguments in a list:
subprocess.Popen([tar_exe, '-tf', image_file])
If you take a look at the subprocess documentation you'll see that arguments must be provided to subprocess commands in the form of a list, so your code sample should look like
def start_phone(image_file):
subprocess.Popen([tar_exe, "-tf", image_file])

How to avoid Shell Injection with a path variable and wait for command exist?

I need to read the exit of a command (then I have to wait for it in sync way):
import subprocess
subprocess.call('ls ~', shell=True)
My problem is a path like this:
~/testing/;xterm;/blabla
How could I sanitize that string from user (allowing special characters from his language)?
import subprocess
subprocess.call('ls ~/testing/;xterm;/blabla', shell=True) # This will launch xterm
I found escapeshellcmd in PHP, but I didn't find anything in Python.
PS: It's not a duplicate of this:
Because it's the complete path, not the filename.
And I read the os.path and I didn't find a solution.
Thanks in advance!
=======
Pass a list instead of a string. And remove shell=True to make the command are not run by shell. (You need to expand ~ yourself using os.path.expanduser)
import os
import subprocess
subprocess.call(['ls', os.path.expanduser('~') + '/testing/;xterm;/blabla'])
Side note: If you want to get list of filenames, you'd better to use os.listdir instead:
filelist = os.listdir(os.path.expanduser('~') + '/testing/;xterm;/blabla')

how to handle white space in filename when using subprocess in python

I'm using subprocess to remove files in python, some of the file name has white space in it. How could I handle this?
For example, I have a file named '040513 data.txt'
subprocess.call(['rm', '040513 data.txt'], shell=True)
But I got error like IOError: [Errno 2] No such file or directory
How could I fix this?
You can also pass a list of args to call. This takes cares of parameters and also you avoid the shell=True security issue:
subprocess.call(['rm', '040513 data.txt'])
If for any reason you wanted to use shell=True then you could also use quotes to escape blanks as you would do in a shell:
subprocess.call('rm "040513 data.txt"', shell=True)
You can escape the whitespace, something like:
cmd = "rm 040513\ data.txt"
subprocess.call(cmd, shell=True)

Windows error and python

I'm working on a bit of code that is supposed to run an exe file inside a folder on my system and getting an error saying...
WindowsError: [Error 3] The system cannot find the path specified.
Here's a bit of the code:
exepath = os.path.join(EXE file localtion)
exepath = '"' + os.path.normpath(exepath) + '"'
cmd = [exepath, '-el', str(el), '-n', str(z)]
print 'The python program is running this command:'
print cmd
process = Popen(cmd, stderr=STDOUT, stdout=PIPE)
outputstring = process.communicate()[0]
I have imported subprocess and also from subprocess import *
For example, This is how my exe file location looks like in the first line of the code I show:
exepath= os.path.join('/Program Files','next folder','next folder','blah.exe')
Am I missing something?
You need to properly escape the space in the executable path
Besides properly escaping spaces and other characters that could cause problems (such as /), you can also use the 8 character old DOS paths.
For example, Program Files would be:
Progra~1 , making sure to append ~1 for the last two characters.
EDIT: You could add an r to the front of the string, making it a raw literal. Python would read the string character for character. Like this:
r " \Program files"
If I remember correctly, you don't need to quote your executuable file path, like you do in the second line.
EDIT: Well, just grabbed nearby Windows box and tested this. Popen works the same regardless the path is quoted or not. So this is not an issue.
AFAIK, there is no need to surround the path in quotation marks unless cmd.exe is involved in running the program.
In addition, you might want to use the environment variable ProgramFiles to find out the actual location of 'Program Files' because that depends on regional settings and can also be tweaked using TweakUI.

When I write a python script to run Devenv with configure "Debug|Win32" it does nothing

Update: When I use the subprocess.call instead of subprocess.Popen, the problem is solved - does anybody know what's the cause? And there came another problem: I can't seem to find a way to control the output... Is there a way to redirect the output from subprocess.call to a string or something like that? Thanks!
I'm trying to use Devenv to build projects, and it runs just fine when i type it in command prompt like devenv A.sln /build "Debug|Win32" - but when I use a python to run it using Popen(cmd,shell=true) where cmd is the same line as above, it shows nothing. If I remove the |, change it to "Debug" only, it works....
Does anybody know why this happens? I've tried putting a \ before |, but still nothing happened..
This is the code I am using:
from subprocess import Popen, PIPE
cmd = ' "C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE\\devenv" solution.sln /build "Debug|Win32" '
sys.stdout.flush()
p = Popen(cmd,shell=True,stdout=PIPE,stderr=PIPE)
lines = []
for line in p.stdout.readlines():
lines.append(line)
out = string.join(lines)
print out
if out.strip():
print out.strip('\n')
sys.stdout.flush()
...which doesn't work, however, if I swap Debug|Win32 with Debug, it works perfectly..
Thanks for every comment here
There is a difference between devenv.exe and devenv.com, both of which are executable and live in the same directory (sigh). The command lines used in the question and some answers don't say which they want so I'm not sure which will get used.
If you want to call from the command line then you need to ensure you use devenv.com, otherwise you're likely to get a GUI popping up. I think this might be the cause of some (but not all) of the confusion.
See section 17.1.5.1. in the python documentation.
On Windows, Python automatically adds the double quotes around the project configuration argument i.e Debug|win32 is passed as "Debug|win32" to devenv. You DON'T need to add the double quotes and you DON'T need to pass shell=True to Popen.
Use ProcMon to view the argument string passed to devenv.
When shell = False is used, it will treat the string as a single command, so you need to pass the command/arugments as a list.. Something like:
from subprocess import Popen, PIPE
cmd = [
r"C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv", # in raw r"blah" string, you don't need to escape backslashes
"solution.sln",
"/build",
"Debug|Win32"
]
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
out = p.stdout.read() # reads full output into string, including line breaks
print out
try double quoting like: 'devenv A.sln /build "Debug|Win32"'
Looks like Windows' shell is taking that | as a pipe (despite the quotes and escapes). Have you tried shell=False instead?

Categories