I am trying to write a python script that sends a string to a program and puts it in the background. On the command line, I can copy and paste the following code and have it successfully do what I want the python program to do:
printf "f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n" | vpfit95
where: vpfit95 is an alias to an executable program in my PATH.
A few permutations of what I’ve tried (tried one at a time):
import subprocess
vpfitExecutable = 'vpfit95'
String1=r'f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n'
String2=r"f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n"
String3="f\nil\ncs\n1.e-8 100.0 1.e-8\nn\n0.002\nb\n0.05\nz\n2.e-7\nx4\n5.e-7\n\n\nfort.13\nn\nn\n\n"
cmd1 = "printf \"" + String1 + "\""
cmd2 = "printf \"" + String1 + "\" | " + vpfitExecutable
cmd3 = "printf \"" + String2 + "\""
cmd4 = "printf \"" + String3 + "\""
print cmd2
p1 = subprocess.Popen([vpfitExecutable, cmd1])
p2 = subprocess.Popen([cmd2])
p3 = subprocess.Popen([vpfitExecutable, cmd3])
p4 = subprocess.Popen([vpfitExecutable, cmd4])
p4 = subprocess.Popen([vpfitExecutable, String1])
p5 = subprocess.Popen([vpfitExecutable, String2])
p6 = subprocess.Popen([vpfitExecutable, String3])
# check
p7 = subprocess.Popen([vpfitExecutable]) # works.
And all fail (except p7). Some fail with a “Fortran runtime error: End of file” (which is from the vpfit program). Others fail with a Traceback to the subprocess library and “OSError: [Errno 2] No such file or directory”.
Some checks: When I print cmd2 and copy and paste it into the terminal, it works perfectly. When I run p7, it correctly starts running the program as expected, just without the string fed to it. I’m obviously missing something fundamental here, and I just can’t figure out what. Any help appreciated!
Yes, you are missing something fundamental – pipes are handled by the shell. To do what you want with subprocess, you should run the
vpfit95as a subprocess, and thencommunicatewith it. See section 17.1.4.2 of the docs, replacing a shell pipeline.If you need to inspect the stdout and stderr of vpfit, then grab the handles from the output tuple of
communicate.A dirty alternative is to run your command with
shell=True, which spawns it inside a shell and then you can use a pipe in your command, but it is cleaner to “cut out the middleman” and interact with the subprocess directly.