Search code examples
pythonsubprocess

How to run bash shell echo in subprocess.run?


On a Raspbian Stretch Linux, this echo command runs fine in the bash shell:

$ echo -n -e "Hello World\n"
Hello World

Now, I want to execute this same command via Python 3's subprocess.run, passed as an array/list; however:

$ python3 -c 'import subprocess; result=subprocess.run(["echo", "-n", "-e", r"Hello World\n"], shell=True, check=True, stdout=subprocess.PIPE); print(result.stdout)'
b'\n'

... I just get a measly linefeed as output ?! Why - and how can I get the full output that I expect?

Note that the Python 3 version here is:

$ python3 --version
Python 3.5.3

Solution

  • shell=True
    

    You are running the shell.

    You are running sh -c echo -n -e $'Hello World\n'. I.e. running subprocess.run(["sh", "-c, "echo", "-n", "-e", r"Hello World\n"]). (Note: it might not be sh and might not be bash.)

    That results in executing program sh with 5 arguments. The interpreter sh executes a script echo which results in a single empty line. The arguments -n -e Hello World are passed as arguments to sh and then ignored. See man sh or man bash section about -c option.

    Compare in shell sh -c echo 123 with sh -c 'echo 123'. Use set -x to debug.

    I guess most probably, you intended to:

    subprocess.run("echo -n -e \"Hello World\\n\"", shell=True...
    

    Which would be equal to:

    subprocess.run(["echo -n -e \"Hello World\\n\""], shell=True...
    

    Or you intended to execute the program echo (not to be confused with Bash shell built-in echo):

    subprocess.run(["echo", "-n", "-e", "Hello World\\n"])  # implicit shell=False
    

    Note that echo options are not portable, see https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html "Application Usage" section. The -n -e may not work correctly, in particular the executable echo (i.e. /usr/bin/echo or /bin/echo) may parse arguments differently from Bash shell builtin echo. You would use printf to be portable, but hopefully this is only a showcase example.

    Also, you might interested in subprocess.check_output.