I am pretty new to python and I am stuck with something now. I am using python 2.7. I am trying to automate a command in shell for which I wrote a python script. I have to input
Pipes are byte streams in Unix. There is no numeric input -- there is only "string" input (there are no numbers or anything else -- there are only bytes).
If your child java process expects a number as its ascii representation then .communicate(input='2')
is correct already if the subprocess reads from stdin (System.in
). If the java process reads from the console directly (System.console().readLine()
) then stdin=PIPE
won't work (you might need to provide a pty in this case e.g., using pexpect).
For example, to read an integer from stdin and print it back in Java:
import java.util.Scanner;
public class ReadInteger
{
public static void main(String args[])
{
Scanner in = new Scanner(System.in);
int i = in.nextInt();
System.out.println("got " + i);
}
}
To pass an integer from Python process to the Java process via a pipe:
#!/usr/bin/env python2
from subprocess import Popen, PIPE
p = Popen(['java', '-ea', 'ReadInteger'], stdin=PIPE, stdout=PIPE)
output = p.communicate(input='2')[0]
print 'from java {' + output.strip() + '}'
It works (the output is from java {got 2}
).
It stops working if the child process reads from the console instead:
public class ReadIntegerConsole
{
public static void main(String args[])
{
int i = Integer.parseInt(System.console().readLine());
System.out.println("got " + i);
}
}
The same python script leads to NullPointerException
(and the output is from java {}
) because System.console()
is null here (stdin is redirected). It works if we provide a pseudo-tty:
#!/usr/bin/env python2
import pexpect # $ pip install pexpect
child = pexpect.spawn('java -ea ReadIntegerConsole')
child.setecho(False)
child.sendline('2')
child.expect(pexpect.EOF)
child.close()
print "from java {" + child.before.strip() + "}"
It works (the output is from java {got 2}
).
Finally I found the solution for this. Well the solution to this was pretty simple
when I changed
string = proc.communicate(input='2')
to
string = proc.communicate(input='2\n')
it worked fine.
The ./sbt
process you are calling needs to be able to read a string and convert it into a integer. It is not possible to send native Python types to a child process with only Popen
.
Another potential solution would be to serialize the data into JSON, YAML, XML, python pickle format, etc - choose your standard. However as you are passing a single integer this would seem very much overkill.