I cannot get it it's bash related or python subprocess, but results are different:
>>> subprocess.Popen("echo $HOME", shell=True, stdout=subprocess.PIPE).communicate()
(b'/Users/mac\n', None)
>>> subprocess.Popen(["echo", "$HOME"], shell=True, stdout=subprocess.PIPE).communicate()
(b'\n', None)
Why in second time it's just newline? Where argument are falling off?
When you have
shell=True
, actual process that runs is the shell process i.e., think of it running/bin/sh -c
on unix. The arguments you pass to Popen are passed as arguments to this shell process. So/bin/sh -c 'echo' '$HOME'
prints newline and the second argument is ignored. So usually you should only use string arguments withshell=True
.The first argument to
subprocess.Popen()
tells the system what to run.When it is a list, you need to use
shell=False
. It coincidentally happens to work as you hope in Windows; but on Unix-like platforms, you are simply passing in a number of arguments which will typically get ignored. Effectively,which simply causes the second argument to not be used for anything (where I use single quotes to emphasize that these are just static strings).
In my humble opinion, Python should throw an error in this case. On Windows, too. This is an error which should be caught and reported.
(In the opposite case, where
shell=False
is specified but the string you pass in is not the name of a valid command, you will get an error eventually anyway, and it makes sense if you have even a vague idea of what's going on.)If you really know what you are doing, you could cause the first argument to access subsequent arguments; for example
would print
foo
,bar
, andbaz
on separate lines. (The "zeroth" argument - here,'ick'
- is used to populate$0
.) But this is just an obscure corollary; don't try to use this for anything.As a further aside, you should not use
subprocess.Popen()
if you just want a command to run. Thesubprocess.run()
documentation tells you this in some more detail. Withtext=True
you get a string instead of bytes.And of course,
os.environ['HOME']
lets you access the value of$HOME
from within Python. This also allows you to avoidshell=True
which you usually should if you can.In the documentation found on https://docs.python.org/2/library/subprocess.html#popen-constructor, if you look at the
shell
argument you will findWhich means that when you execute the second command it runs as
echo
and hence you get just a new line.