I have a problem with the following code:
import subprocess
process = subprocess.run(
['mkdir', 'hola'], stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True
)
print(process.stderr)
print(process.stdout)
It does not create the "hello" folder, but the strange thing is that the process gives the following error:
b"mkdir: falta un operando\nPruebe 'mkdir --help' para m\xc3\xa1s informaci\xc3\xb3n.\n" # print(process.stderr)
It's like passing it as the first parameter ['mkdir']
instead of ['mkdir', 'hola']
, but I don't know.
Also try the following: ['cp', 'file1.txt', 'file2.txt']
and something similar happened:
b"cp: falta un fichero como operando\nPruebe 'cp --help' para m\xc3\xa1s informaci\xc3\xb3n.\n"
What's going on? (a few days ago, it worked fine... and I have no idea why it doesn't work now)
When you try to execute a command with the argument
shell=True
, what you do is run the shell passing the list of arguments. Which command interpreter? It depends on your operating system, how you have it configured; on Linux at least there are plenty of shells to choose from.On Linux, the shell is determined by the environment variable
$SHELL
. On my PC, running Linux Mint, it$SHELL
points to/bin/bash
.Now,
bash
it is called with this format:which tells us that it expects an invocation by optionally passing a string containing the command to execute. In this case, I also have to use the option
-c
to indicate that a string follows with the command. So if you want to create a directory, I have to type on the command line:Far-fetched, but illustrates the point.
Alternative
shell=True
You only need to invoke the with command
shell=True
if you want the shell to perform some actions of its own, like expanding environment variables or converting ambiguous file specifications (like*.lst
) into an explicit list.In this case, you must pass a single string with the entire command:
['mkdir hola']
Alternative
shell=False
In your case, you don't need any of that. You can say
shell=False
, or omit the e execute parameter byrun
passing an array with each element separately:['mkdir', 'hola']
Example
I want to list all
.txt
in my directory.I can do it with
ls *.txt
, but that requires expanding*.txt
, which is the shell's job:produces:
What happens if I do it with
shell=False
produces:
because the program
ls
received as an argument*.txt
and that is a file that does not exist. Remember that in Linux it is the shell that expands*.txt
before executing the program.Moral: Skip
shell=True