7

I'm trying to use Python to automate a process that involves calling a Fortran executable and submitting some user inputs. I've spent a few hours reading through similar questions and trying different things, but haven't had any luck. Here is a minimal example to show what I tried last

#!/usr/bin/python

import subprocess

# Calling executable 
ps = subprocess.Popen('fortranExecutable',shell=True,stdin=subprocess.PIPE)
ps.communicate('argument 1')
ps.communicate('argument 2')

However, when I try to run this, I get the following error:

  File "gridGen.py", line 216, in <module>
    ps.communicate(outputName)
  File "/opt/apps/python/epd/7.2.2/lib/python2.7/subprocess.py", line 737, in communicate
    self.stdin.write(input)
ValueError: I/O operation on closed file

Any suggestions or pointers are greatly appreciated.

EDIT:

When I call the Fortran executable, it asks for user input as follows:

fortranExecutable
Enter name of input file: 'this is where I want to put argument 1'
Enter name of output file: 'this is where I want to put argument 2'

Somehow, I need to run the executable, wait until it asks for user input and then supply that input.

James
  • 167
  • 2
  • 2
  • 6

4 Answers4

8

If the input doesn't depend on the previous answers then you could pass them all at once using .communicate():

import os
from subprocess import Popen, PIPE

p = Popen('fortranExecutable', stdin=PIPE) #NOTE: no shell=True here
p.communicate(os.linesep.join(["input 1", "input 2"]))

.communicate() waits for process to terminate therefore you may call it at most once.

jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • it says like this for me `TypeError: a bytes-like object is required, not 'str'` – Mohith7548 Aug 07 '18 at 15:55
  • 1
    @KuneMohith the code is for Python 2 (where `str` is `bytes` type). Pass `text=True` or `encoding` parameter to Popen() on the current Python version. – jfs Aug 07 '18 at 18:49
  • 1
    @KuneMohith: e.g., `subprocess.run('fortranExecutable', input="\n".join(["input 1", "input 2"]), text=True)` (tested on Python 3.7) – jfs Aug 08 '18 at 17:44
1

As the spec says communicate() awaits for the subprocess to terminate, so the second call will be addressed to the finished process.

If you want to interact with the process, use p.stdin&Co instead (mind the deadlock warning).

bereal
  • 32,519
  • 6
  • 58
  • 104
0

By the time, you reach ps.communicate('argument 2'), ps process is already closed as ps.communicate('argument 1') waits until EOF. I think, if you want to write multiple times at stdin, you might have to use:

ps.stdin.write('argument 1')
ps.stdin.write('argument 2')
venpa
  • 4,268
  • 21
  • 23
-1

your arguments should not be passed to communicate. they should be given in the call to Popen, like: http://docs.python.org/2/library/subprocess.html#subprocess.Popen

>>> import shlex, subprocess
>>> command_line = raw_input()
/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'"
>>> args = shlex.split(command_line)
>>> print args
['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]
>>> p = subprocess.Popen(args) # Success!
Colin Bernet
  • 1,354
  • 9
  • 12
  • The problem is that the executable runs and then asks for user input. I need to wait until the user input is requested and then fill in that input. There are three inputs total. – James Feb 03 '14 at 08:17