Avoiding shell=True in Popen - python

I am trying to open a .txt file in Windows. The code is as follows:
subprocess.Popen("C:\folder\file.txt", shell=True)
This works perfectly fine. The default editor is automatically opened and the file is loaded, however, I have read somewhere before that invoking calls through the shell (cmd.exe in Windows) is less safe. How can I do the same without it. Simply setting shell=False is giving me the error:
OSError: [WinError 193] %1 is not a valid Win32 application
Now, I can try this as a workaround:
subprocess.Popen("notepad C:\folder\file.txt")
but this only works if notepad is available, hence loses its generality.

If you are using windows then there is the (non portable) os.startfile command which will take a file path and open it in the default application for that filetype.
In your case you would do:
import os
os.startfile("C:\folder\file.txt")
Note that this method won't work on Linux and Mac OSX, you'll have to have to use their own utilities for this. (open for OSX and xdg-open on Linux) and start them with subprocess.

The feature you try to use is a builtin thing of the windows cmd.exe. Therefore you need to set the shell=True parameter. The cmd.exe knows what to do with the file you hand in.
If you use shell=False, you try to start the file like a programm and hence nothing happens, since .txt files have no exe-header.
Read more about it in the documentation.
Reading further, you can find why using the shell=True parameter can be a security flaw. If you consider to assemble the parameters by user inputs, you should not use this, otherwise nothing speaks against it.
Anyway, I recommend using your second example, because it is explicit. You decide what program to start.
subprocess.Popen("notepad C:\folder\file.txt")

Related

Open a Windows shortcut file `.lnk` with subprocess

I am fairly new to Python and have been trying to make a program that will open the "Minecraft launcher" for me.
Context
However, the new launcher .exe file is blocked as it is located in the windowsapp file which requires a lot of faffing about that I would rather avoid, so instead I was hoping to see if I could open the desktop shortcut instead to open the launcher directly?
Error
This code so far doesn't work as it gives me the error:
OSError: [WinError 193] %1 is not a valid Win32 application
Code
import time
import subprocess
subprocess.Popen('C:/Users/(my username)/Desktop/Minecraft Launcher.lnk')
I have tried subprocess.call however that doesn't seem to work either.
.lnk files are interpreted by the shell. So, enable the shell:
subprocess.call("C:\\Users\\My Username\\Desktop\\Minecraft Launcher.lnk", shell=True)
As a side note, the shell is one of the very few things in Windows that insists on backslashes.

How to open xlsx file in LibreOffice on Ubuntu?

I want to open a file in LibreOffice Calc on Ubuntu after working on it through Python.
How would I go about this?
I tried:
import subprocess
subprocess.call("explorer path-to-file")
# got error that the path doesn't exist
subprocess.call("calc path-to-file")
# Calc is not executable type error
You could use the xdg-open tool (if you have it) to use the default tool for the file type, or if you really want to always use Libreoffice, the executable for it is libreoffice.
os.system("xdg-open path-to-file")
os.system("libreoffice path-to-file")
(and as always when using os.system(), make sure path-to-file comes from a trusted source.)

How to launch a program with many arguments in Python/Linux

The following code works fine in Windows:
subprocess.Popen([PATH_TO_G++]/g++ file.cpp -o file.exe)
However in Linux I get the following error:
OSError: [Errno 2] No such file or directory
After reading the documentation and several SO threads, I found out that subprocess.Popen works differently in Windows and nix systems. In windows it takes the string as the parameter and launches it just like you'd launch it in terminal.
In linux however it requires a list of strings if you have parameters. The first value is the program itself, then go the attributes. You can make it behave like Windows by passing the Shell=True argument, but that's not a good solution for me.
I tried the shlex.split function, but it still doesn't work.
Based on your example you'll need to make sure the command is properly quoted:
subprocess.Popen([PATH_TO_G++ + "/g++", "file.cpp", "-o", "file.exe"])
There is no way PATH_TO_G++ is a valid variable name, so I'm just going to assume that you provided that as an example.
Now, more importantly, what are you trying to do with the subprocess? Just launch it and have it be the primary operation? Launch it and capture the output? Launch it in the background?
The documentation for the subprocess module is pretty clear and provides a lot of examples on how you might use it.

WinCVS - Python - TCL

I have got a list of files in txt files and I need to check them out in edit mode, and make some changes(there are word documents), and check them back in via WinCVS.
I know I can write tcl scripts or macro, or python scripts in wincvs shell but I have some problems with them.
I have installed TCL 8.5 and selected tcl DLL in Admin>Preferences, tcl is now available, but whenever I type and execute a tcl script, it says
can not find channel named "stdout"
Do you have any idea regarding this error?
Also, I cannot see admin macros, it says Shell is not available. I have installed the latest version of python and select related dll in preferences.
Could anyone give me a hint for checking a list of files via wincvs?
many thanks in advance,
regards
The problem is that Tcl's trying to build the standard file descriptors into available-by-default channels (i.e., stdin, stdout and stderr) but this goes wrong when they're not opened by default. That's the case on Windows when running disconnected (which is what happens inside GUI applications on that platform). When you're running with a full Tcl shell such as wish, this is worked around, but you're embedded so that's not going to work; the code to fix things isn't run because it's part of the shell startup and not the library initialization (after all, replacing a process-global resource like file descriptors is a little unfriendly for any library to do without the app or user asking it to!)
The simplest workaround is to not write to stdout – note that it's the default destination of the puts command, so you have to be careful – and to take care not to write to stderr either, as that's probably under the same restrictions (which means that you've got to be careful how you trap errors, especially while testing your script).

Windows can't find the file on subprocess.call()

I am getting the following error:
WindowsError: [Error 2] The system cannot find the file specified
My code is:
subprocess.call(["<<executable file found in PATH>>"])
Windows 7, 64 bit. Python 3.x latest, stable.
Any ideas?
Thanks,
When the command is a shell built-in, add a shell=True to the call.
E.g. for dir you would type:
import subprocess
subprocess.call('dir', shell=True)
To quote from the documentation:
The only time you need to specify shell=True on Windows is when the command you wish to execute is built into the shell (e.g. dir or copy). You do not need shell=True to run a batch file or console-based executable.
On Windows, I believe the subprocess module doesn't look in the PATH unless you pass shell=True because it use CreateProcess() behind the scenes. However, shell=True can be a security risk if you're passing arguments that may come from outside your program. To make subprocess nonetheless able to find the correct executable, you can use shutil.which. Suppose the executable in your PATH is named frob:
subprocess.call([shutil.which('frob'), arg1, arg2])
(This works on Python 3.3 and above.)
On Windows you have to call through cmd.exe. As Apalala mentioned, Windows commands are implemented in cmd.exe not as separate executables.
e.g.
subprocess.call(['cmd', '/c', 'dir'])
/c tells cmd to run the follow command
This is safer than using shell=True, which allows shell injections.
If you are using powershell, then in it will be subprocess.call(['powershell','-command','dir']). Powershell supports a large portion of POSIX commands
After much head scratching, I discovered that running a file that is located in C:\Windows\System32\ while running a 32bit version of python on a 64bit machine is a potential issue, due to Windows trying to out-smart the process, and redirect calls to C:\Windows\System32 to C:\Windows\SysWOW64.
I found an example of how to fix this here:
http://code.activestate.com/recipes/578035-disable-file-system-redirector/
To quote from the documentation:
"Prior to Python 3.5, these three functions comprised the high level API to subprocess. You can now use run() in many cases, but lots of existing code calls these functions."
SO: instead of subprocess.call use subprocess.run for Python 3.5 and above
I met the same issue while I was calling a PHP. The reason is PHP isn't in PATH so the command PHP was not found. But PowerShell found it does exist in the current location and it suggests replacing the 'PHP' by the '.\PHP' if I trust this command. Then it runs well.

Categories

Resources