Python subprocess with heredocs

I've been playing around with the Python subprocess module, tried a few examples, but I can't seem to get the heredoc commands to work.

Here's a trivial example I played with:

import subprocess
a = "A String of Text"
p = subprocess.Popen(["cat", "<<DATA\n" + a + "\nDATA"])

      

I am getting the following error when running the code above:

cat: <<DATA\nA String of Text\nDATA: No such file or directory

      

Am I doing it wrong? Is it possible? If so, how do I do it?


Update

Just wanted to say this should never be done in a real python program because there are better ways to do it.

+2


source to share


3 answers


Shell support "heredoc" is a shell. subprocess.Popen

does not run your command through the default shell, so this syntax will of course not work.

However, since you are using pipes anyway, there is no need to use the shell's heredoc support. Just write a line a

in the stdin pipe of the process you just started. This is exactly what the shell will do with heredoc anyway.

You can do it with Popen.communicate()

:



p.communicate(a)

      

The return value of the function communicate()

contains the output of the process (in two streams, see docs).

+4


source


As others have pointed out, you need to run it in a shell. Popen does this easily with the shell = True argument. I am getting the following output:



>>> import subprocess
>>> a = "A String of Text"
>>> p = subprocess.Popen("cat <<DATA\n" + a + "\nDATA", shell=True)
>>> A String of Text

>>> p.wait()
0

      

+3


source


You are passing shell syntax as an argument to the program cat

. You can try doing it like this:

p = subprocess.Popen(["sh", "-c", "cat <<DATA\n" + a + "\nDATA"])

      

But the concept itself is wrong. You should use Python functions instead of calling shell scripts inside your python scripts.

And in this particular case, you have to have the shell heredoc syntax interpolate the variables, so you need to escape all the text inside a

and make sure there is no line in it DATA

.


For the Python equivalent, I think the closest idea to this (if you don't want to just print(a)

;-)) is passing the value of the variable to the stdin of the spawned process:

p = subprocess.Popen(["program", ...], stdin=subprocess.PIPE)
p.communicate(a)

      

+2


source







All Articles