Interact with terminal application Java or C++ - java

I'm trying to make a GUI that will interact with a terminal-based program, in this case the geth console for Ethereum. I'm able to start it up, but I have no idea how to send commands or retrieve output once it's running.
I've tried other programs, like Vim, but everything is totally separate from my program after it's started and I'm unable to give it any further commands.
After searching StackOverflow and matching solutions together, this is what I've come up with, and it's the closest I've come to success.
public static void main(String[] args) throws IOException{
String[] command = {"gnome-terminal", "-e", "vim temp.txt"};
Process proc = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream()));
writer.write(":x");
writer.flush();
writer.close();
}
}
This will start Vim, creating temp.txt, but then Vim just sits open and the writer does nothing.
Is what I'm trying to do even possible?
P.S. I'm okay with C++, but I'd prefer Java for this as I'm more familiar with it.

On the GO-Ethereum Wiki it says that it supports:
a JavaScript Console. You'd have to write the app in JavaScript itself - probably not an option here;
a JSON RPC server, in which case you'd communicate over a socket, not STDIN/OUT;
Commandline Options, in which case you would
String[] command = {"geth", "help" };

Related

Passing data from Java process to a python script

I call a external Python script as Java process and want to send data to this. I create a process and try to send a string. Later the python script should wait for a new input from Java, work with this data and wait again(while true loop).
Python Code (test.py):
input = input("")
print("Data: " + input)
Java Code:
Process p = Runtime.getRuntime().exec("py ./scripts/test.py");
BufferedWriter out = new BufferedWriter(new
OutputStreamWriter(p.getOutputStream()));
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
System.out.println("Output:");
String s = null;
out.write("testdata");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
The process and output of simple prints works, but not with input and BufferedWriter.
Is it possible to send data to this python input with a Java process?
I read from other solutions:
create a Python listener and send messages to this script
import the external script to Jython and pass data
Are this better solutions to handle my problem?
use Process class in java
what is process class ?
this class is used to start a .exe or any script using java
How it can help you
Create your python script to accept command line variables and send your data from java class to python script.
for Example:
System.out.println("Creating Process");
ProcessBuilder builder = new ProcessBuilder("my.py");
Process pro = builder.start();
// wait 10 seconds
System.out.println("Waiting");
Thread.sleep(10000);
// kill the process
pro.destroy();
System.out.println("Process destroyed");
Later the python script should wait for a new input from Java
If this has to happen while the python process is still a subprocess of the Java process, then you will have to use redirection of I/O using ProcessBuilder.redirect*( Redirect.INHERIT ) or ProcessBuilder.inheritIO(). Like this:
Process p = new ProcessBuilder().command( "python.exe", "./scripts/test.py" )
.inheritIO().start();
If the python process is going to be separate (which is not the case here, I think) then you will have to use some mechanism to communicate between them like client/server or shared file, etc.

Using SSMTP and ProcessBuilder

I'm currently working on a project for school and I'm trying to use sSMTP to send emails from java to a user using a text file. Executing from the command line ssmtp email#gmail.com < msg.txt works just fine and sends me the email with the information contained in msg.txt. However, when I try to do it in java using ProcessBuilder it doesn't send an email.
`ProcessBuilder builder = new ProcessBuilder;
builder.command("ssmtp", "email#gmail.com", "<", "msg.txt");
Process p = builder.start();`
I believe that it doesn't like where I try to pipe in msg.txt. If anyone knows a better way to do this that would be great. I haven't been able to find anything yet and am not sure how to do it myself
Instead of trying to rely on the shell's redirect functionality (which as you see doesn't work), you can just read msg.txt and write it to the process' OutputStream. It'll be the same thing, but in code (and it'll be a better solution too).
Something along the lines of
Process p = new ProcessBuilder("ssmtp").start();
PrintStream out = new PrintStream(p.getOutputStream());
String line = null;
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream("msg.txt")));
while((line = in.readLine()) != null)
out.println(line);
out.close();
in.close();
However if you want to use shell redirection which I wouldn't recommend for anything serious, you need to execute the program which actually does the redirection, i.e. bash. The following should do the trick:
new ProcessBuilder("bash", "ssmtp", "email#gmail.com", "<", "msg.txt").start();
As dave_thompson_085 commented, it's even easier to do programmatic redirection. Things sure are easy these days!
new ProcessBuilder("ssmtp", "email#gmail.com").redirectInput(new File("msg.txt")).start();

How do I read and write from an external process in Java?

I want to run PianoBar from a Java GUI (PianoBar is a program that runs Pandora from command line). I thought this would be quick and dirty, but I guess I don't know enough about interaction between programs.
I use ProcessBuilder to launch an instance of PianoBar like so:
private Process createPianoBarProcess() throws IOException {
String[] command = {"CMD", "/C", "pianobar"};
ProcessBuilder probuilder = new ProcessBuilder( command );
probuilder.redirectErrorStream(true);
probuilder.directory(new File("~~location where pianobar.exe is~~"));
Process process = probuilder.start();
return process;
}
After I create the process, I create a BufferedReader to read in the PianoBar output:
Process pianoBar = createPianoBarProcess();
InputStream inS = pianoBar.getInputStream();
InputStreamReader isr = new InputStreamReader(inS);
BufferedReader br = new BufferedReader(isr);
But when I read the output from PianoBar via this reader, it spits out the first line of PianoBar ("Welcome to pianobar (2013.05.19-win32)! Press ? for a list of commands."), then it spits out the next line ("[?] Email:"). Then it just hangs.
Obviously, it is waiting for the user to input their email. But no matter what I try, I can't get my Java program to write the email to the PianoBar process when prompted - it just hangs as soon as it reads out the last character.
Is it possible to do what I am trying to do? I thought it would be an easy thing to look for on the internet, but I haven't been able to find anything. All I want is an easy way to write to the external process when prompted. Seems like this should be easy...
You may use the following code snippet to get working:
String s;
//s = email
BufferedWriter bufferedwriter = new BufferedWriter(new OutputStreamWriter(pianoBar.getOutputStream()));
bufferedwriter.write(s);
bufferedwriter.flush();
Done!
Remember to surround the code block with appropriate try/catch

Calling Python from Java (Tomcat6) as sub-process

I am trying to call a python script from a java/tomcat6 webapp. I am currently using the following code:
Process p = Runtime.getRuntime().exec("python <file.py>");
InputStream in = p.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader b = new BufferedReader(isr);
logger.info("PYTHON OUTPUT");
String line = null;
while ( (line = b.readLine()) != null){
logger.info(line);
}
p.waitFor();
logger.info("COMPLETE PYTHON OUTPUT");
logger.info("EXIT VALUE: "+p.exitValue());
I can't really see any output in the catalinia.out file from the python script and using an adapter library like jython is not possible as the script relies on several machine learning libraries that need python's Numpy module to work.
Help?
The explanation is probably one (or more) of following:
The command is failing and writing error messages to its "stderr" fd ... which you are not looking at.
The command is failing to launch because the command name is incorrect; e.g. it can't be found on $PATH.
The command is trying to read from its stdin fd ... but you haven't provided any input (yet).
It could be a problem with command-line splitting; e.g if you are using pathnames with embedded spaces, or other things that would normally be handled by the shell.
Also, since this is python, this could be a problem with python-specific environment variables, the current directory and/or the effective user that is executing the command.
How to proceed:
Determine if the python command is actually starting. For instance. "hack" the "" to write something to a temporary file on startup.
Change to using ProcessBuilder to create the Process object. This will give you more control over the streams and how they are handled.
Find out what is going to the child processes "stderr". (ProcessBuilder allows you to redirect it to "stdout" ...)

External program from our Java program

How can I write a program in Java that will execute another program? Also, the input of that program should be given from our program and the output of that program should be written into a file.
This is my small set of code to get its output:
Process p = Runtime.getRuntime().exec("C:\\j2sdk1.4.0\bin\\helloworld.java");
BufferedReader input =
new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null)
System.out.println(line);
input.close();
This was my set of code but this throws an IOException.
The API that Java offers for this is the ProcessBuilder. It is relatively straightforward to set working directory and pass parameters.
What is a little tricky is passing STDIN and reading STDERR and STDOUT, at least for non-trivial sizes thereof, because you need to start seperate threads to make sure the respective buffers get cleared. Otherwise the application that you called might block until it can write more output, and if you also wait for that process to finish (without making sure that STDOUT gets read), you will deadlock.
You can use java.lang.Process and java.lang.ProcessBuilder. You interact with the input/output of the process using getInputStream/getOutputStream/getErrorStream.
However, there's an Apache Commons library called Exec which is designed to make all of this easier. (It can normally get quite hairy when it comes to quoting command line parameters etc.) I haven't used Exec myself, but it's worth checking out.
When you only want to start other programms, you can use the exec method like this:
Runtime r = Runtime.getRuntime();
mStartProcess = r.exec(applicationName, null, fileToExecute);
StreamLogger outputGobbler = new StreamLogger(mStartProcess.getInputStream());
outputGobbler.start();
int returnCode = mStartProcess.waitFor();
class StreamLogger extends Thread{
private InputStream mInputStream;
public StreamLogger(InputStream is) {
this.mInputStream = is;
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(mInputStream);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
exec:
public Process exec(String command, String envp[], File dir)
#param command a specified system command.
#param envp array of strings, each element of which
has environment variable settings in format
<i>name</i>=<i>value</i>.
#param dir the working directory of the subprocess, or
<tt>null</tt> if the subprocess should inherit
the working directory of the current process.
Please do not edit your question so that it does not fit the original answers anymore.
If you have follow-up question, clearly mark them as such, or ask them as a seperate questions, or use comments or something.
As for your IOException, please give the error message it shows.
Also, it seems as if you are trying to run a ".java" file directly. That will not work. The methods described here are to launch native binary executables. If you want to run a ".java" file, you have to compile it to a class, and the invoke that class' main method.
What platform are you in?
If you are on *nix you can type:
java MyProgram | myexternalprogram > myfilename.txt

Categories