Getting Output from Continuous (Unending) Terminal Programs in Java - java

Basically I'm running a program that takes continuous input. It doesn't end until you input an "#" symbol and press enter. I am wondering how I can read the output from this program, given that there is currently (what I have inferred is) a "readLine() block" when I try to get the BufferedReader content. Current code is below. I've done it with and without the while loop, and either way the program never reaches an end point, indicating to me it is the readLine() that is the problem.
An example of the program is something like
input a number:
2
You input 2
input a number:
3
You input 3
input a number:
#
exit
That isn't the program, but the basic gist of what it is and how it acts. I need to get every bit of that output. Input is another story; consider it irrelevant to the question for now, as I'm not even there just yet.
My code is below.
ProcessBuilder pb = new ProcessBuilder(cmd);
Process p = pb.start();
BufferedReader terminalOutput = new BufferedReader( new InputStreamReader(p.getInputStream()) );
BufferedWriter terminalInput = new BufferedWriter( new OutputStreamWriter(p.getOutputStream()) );
String line = "";
String s = "";
int count = 0;
line = terminalOutput.readLine();

Related

How to make an input to a started process with ProcessBuilder?

We have a closed-source archive that does only one thing: reads a string input and outs its value hashed. Not by its command arguments, but once it is started and stays continuously open, getting inputs and giving the value properly hashed.
So I want to open it with ProcessBuilder and do the inputs. The problem is that i have tried to input in the process and i have failed:
ProcessBuilder pb = new ProcessBuilder("/path/to/executable");
Process p = pb.start();
OutputStream os = p.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("Hey\n");
String result = read(p);
System.out.println("Out: " + result);
p.destroy();
But looks like i'm not getting any output, first of because the executable is not getting my "Hey".
So the main question is, how do I input into the started program? Any kind of suggestions are welcome.
After
pw.write("Hey\n");
Try doing a
pw.flush();

Java reader does not start printing until closing the programm [duplicate]

I have the following code example below. Whereby you can enter a command to the bash shell i.e. echo test and have the result echo'd back. However, after the first read. Other output streams don't work?
Why is this or am I doing something wrong? My end goal is to created a Threaded scheduled task that executes a command periodically to /bash so the OutputStream and InputStream would have to work in tandem and not stop working. I have also been experiencing the error java.io.IOException: Broken pipe any ideas?
Thanks.
String line;
Scanner scan = new Scanner(System.in);
Process process = Runtime.getRuntime ().exec ("/bin/bash");
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
String input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.flush();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
input = scan.nextLine();
input += "\n";
writer.write(input);
writer.close();
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
Firstly, I would recommend replacing the line
Process process = Runtime.getRuntime ().exec ("/bin/bash");
with the lines
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.redirectErrorStream(true);
Process process = builder.start();
ProcessBuilder is new in Java 5 and makes running external processes easier. In my opinion, its most significant improvement over Runtime.getRuntime().exec() is that it allows you to redirect the standard error of the child process into its standard output. This means you only have one InputStream to read from. Before this, you needed to have two separate Threads, one reading from stdout and one reading from stderr, to avoid the standard error buffer filling while the standard output buffer was empty (causing the child process to hang), or vice versa.
Next, the loops (of which you have two)
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
only exit when the reader, which reads from the process's standard output, returns end-of-file. This only happens when the bash process exits. It will not return end-of-file if there happens at present to be no more output from the process. Instead, it will wait for the next line of output from the process and not return until it has this next line.
Since you're sending two lines of input to the process before reaching this loop, the first of these two loops will hang if the process hasn't exited after these two lines of input. It will sit there waiting for another line to be read, but there will never be another line for it to read.
I compiled your source code (I'm on Windows at the moment, so I replaced /bin/bash with cmd.exe, but the principles should be the same), and I found that:
after typing in two lines, the output from the first two commands appears, but then the program hangs,
if I type in, say, echo test, and then exit, the program makes it out of the first loop since the cmd.exe process has exited. The program then asks for another line of input (which gets ignored), skips straight over the second loop since the child process has already exited, and then exits itself.
if I type in exit and then echo test, I get an IOException complaining about a pipe being closed. This is to be expected - the first line of input caused the process to exit, and there's nowhere to send the second line.
I have seen a trick that does something similar to what you seem to want, in a program I used to work on. This program kept around a number of shells, ran commands in them and read the output from these commands. The trick used was to always write out a 'magic' line that marks the end of the shell command's output, and use that to determine when the output from the command sent to the shell had finished.
I took your code and I replaced everything after the line that assigns to writer with the following loop:
while (scan.hasNext()) {
String input = scan.nextLine();
if (input.trim().equals("exit")) {
// Putting 'exit' amongst the echo --EOF--s below doesn't work.
writer.write("exit\n");
} else {
writer.write("((" + input + ") && echo --EOF--) || echo --EOF--\n");
}
writer.flush();
line = reader.readLine();
while (line != null && ! line.trim().equals("--EOF--")) {
System.out.println ("Stdout: " + line);
line = reader.readLine();
}
if (line == null) {
break;
}
}
After doing this, I could reliably run a few commands and have the output from each come back to me individually.
The two echo --EOF-- commands in the line sent to the shell are there to ensure that output from the command is terminated with --EOF-- even in the result of an error from the command.
Of course, this approach has its limitations. These limitations include:
if I enter a command that waits for user input (e.g. another shell), the program appears to hang,
it assumes that each process run by the shell ends its output with a newline,
it gets a bit confused if the command being run by the shell happens to write out a line --EOF--.
bash reports a syntax error and exits if you enter some text with an unmatched ).
These points might not matter to you if whatever it is you're thinking of running as a scheduled task is going to be restricted to a command or a small set of commands which will never behave in such pathological ways.
EDIT: improve exit handling and other minor changes following running this on Linux.
I think you can use thread like demon-thread for reading your input and your output reader will already be in while loop in main thread so you can read and write at same time.You can modify your program like this:
Thread T=new Thread(new Runnable() {
#Override
public void run() {
while(true)
{
String input = scan.nextLine();
input += "\n";
try {
writer.write(input);
writer.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} );
T.start();
and you can reader will be same as above i.e.
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
make your writer as final otherwise it wont be able to accessible by inner class.
You have writer.close(); in your code. So bash receives EOF on its stdin and exits. Then you get Broken pipe when trying to read from the stdoutof the defunct bash.

Using command prompt with Java

I'm working on a Windows 7 machine.
I'm working on an application which is a front for the GHCi interpreter for Haskell. The user will input a command, then Java will execute the command via the exec() method on Runtime, and then the application will display the text that would display if the user was just running GHCi using command prompt.
Right now, I'm running into issues with the loop that prints the output.
Here is the code I have right now.
public class GHCiTest {
public static Scanner rd, sc;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
try {
System.out.println("Starting... ");
Process p = Runtime.getRuntime().exec("ghci");
PrintStream hugsin = new PrintStream(p.getOutputStream());
InputStream hugsout = p.getInputStream();
sc = new Scanner(hugsout);
rd = new Scanner(System.in);
String rdnextline;
while (true){
while (sc.hasNextLine()){
System.out.println(sc.nextLine());
}
System.out.println("yay");
rdnextline = rd.nextLine();
if (rdnextline == "quit"){break;}
hugsin.println(rdnextline);
hugsin.flush();
}
System.out.println(" ... successful completion.");
}
catch(IOException e) {
e.printStackTrace();
}
}
}
I know that the initial starting of GHCi is working, because the program is printing out "GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help". However, the issue appears to be the while(sc.hasNextLine()) loop, which is supposed to read the output of the command prompt and output it until there's nothing left, as it won't break out of the loop and proceed to read the user input. I know this because the program isn't printing the "yay" flag I put in after the loop.
Receive output of ghci in another thread like this.
System.out.println("Starting... ");
Process p = Runtime.getRuntime().exec("ghci");
PrintStream hugsin = new PrintStream(p.getOutputStream());
InputStream hugsout = p.getInputStream();
Scanner rd = new Scanner(System.in);
new Thread(() -> {
try (Reader r = new InputStreamReader(hugsout)) {
int ch;
while ((ch = r.read()) != -1)
System.out.print((char)ch);
} catch (IOException e ) {}
}).start();
Scanner sc = new Scanner(hugsout);
String rdnextline;
while (true) {
rdnextline = rd.nextLine();
hugsin.println(rdnextline);
hugsin.flush();
if (rdnextline.equals("quit")) {
break;
}
}
System.out.println(" ... successful completion.");
Your loop won't exit until the end of the stream has been reached:
while (sc.hasNextLine()){
System.out.println(sc.nextLine());
}
The end of the stream is the end of your process. So, your Java program is waiting for the sub process to run to completion, and terminate. Once that happens, the loop will end, and the Java program will send the desired commands to the process.
Sorry, I mean, try to send the desired commands to the process; it won't succeed because the process has terminated.
If the GHCi process outputs a "prompt" of some kind, you could try to break your while(...) { print } at that moment, get input from the user, send that to the process, and then loop back and re-enter your while(...) { print }, waiting for the next prompt.
Assuming the prompt does not end with a newline, but rather appears at the start of a line where the user input gets typed, you cannot use a while(sc.hasNextLine()) { ... } type of loop, because the prompt is not a complete line. You might have to resort to reading character by character, looking for the prompt sequence in the last "n" characters.
Looks like you can change the prompt in GHCi. See here for details. If you change the prompt to end with a newline, you could still read the stream in lines.
while (sc.hasNextLine()){
String line = sc.nextLine();
if (line.equals("YourPromptHere"))
break;
System.out.println(line);
}
(Alternately, you might be able to do something with threads to allow both parts to run without blocking each other. Of course, threading comes with its own issues and complexity.)
EDIT
I had a blinding flash of the obvious. Assuming GHC's prompt looks like this ...
GHCi, version 7.10.3
yada, yada, yada ...
Main> _
... you could set the scanner's delimiter to be the prompt string Main>.
// Set scanner delimiter to GHCi's Prompt string
sc = new Scanner(hugsout).setDelimiter("^Main> ");
while (sc.hasNext()) {
// Echo GHCi's output upto the delimiter (prompt)
System.out.println(sc.next());
// Read user input & transfer to GHCi.
System.out.print("Replacement Prompt> ");
rdnextline = rd.nextLine();
if (rdnextline == "quit") {
break;
}
hugsin.println(rdnextline);
hugsin.flush();
}
Note: This does not take into account the secondary prompt, used when GHCi expects more input to complete the command. You could use a regex something like "^Main> |\bAlt> " that matches either prompt, but you would not be able to tell which prompt the delimiter matched.
The first subexpression "^Main> " matches the start of a line, followed by "Main> ", where as the second subexpression "\bAlt> " only matches a word boundary followed by "Alt> ". This is because the output stream of the GHCi, would look like "\nMain> Alt> " with a long pause before the Alt>; the "newline" before Alt> would normally come from the echoing of the Enter keypressed on the input stream.

Sending input to stdin and getting the full output in Java - Festival TTS

I'm trying to use the Java Runtime.getRuntime().exec(String) command to run Festival, then use OutputStreamWriter to write some commands to the outpustream of the process.
This works great, and I'm able to do something like this:
Process p = Runtime.getRuntime().exec("festival");
Writer w = new OutputStreamWriter(p.getOutputStream());
w.append("(SayText \"Hello World\")");
w.flush();
Obviously the way I can tell this works is that it speaks the text through the speakers.
What I am having a real hard time doing is getting the text output from what I would see in the terminal. I'm trying to run some other commands (such as (voice.list)) which output text, presumably to stdout.
For example, I've tried using a BufferedReader in the following way:
BufferedReader reader = new BufferedReader (new InputStreamReader(p.getInputStream()));
w.append("(voice.list)");
w.flush();
String output = "";
String line = reader.readLine();
System.out.println(line);
while ((line = reader.readLine()) != null)
{
System.out.println("Reading: " + line);
output += line;
}
(The System.out.println's is just for debugging, I would do the entire thing in a cleaner way if I was able to get it to work.)
No matter what code I try, I'm never able to get any output from Festival. I can get output from other commands. E.G. I have tried this code as well http://en.allexperts.com/q/Java-1046/2008/2/Runtime-getRuntime-exec-cmd.htm and it works with many other commands (like ls) but not Festival.
Does anything have any idea how I would be able to get this to work?
Thanks.
Festival may output it's text on stderr instead of stdout. Try replacing
p.getInputStream()
with
p.getErrorStream()

Using java to get the current process owner

I want to know the owner of current process in Unix using Java. I want to find the current server's owner name. I tried with running "who am i" command in Runtime.getRuntime().exec(), but its not returning me any results.
String line = "";
Process p = Runtime.getRuntime().exec("who am i");
InputStream iStream = p.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(iStream);
BufferedReader bufReader = new BufferedReader(inputStreamReader);
while ((line = bufReader.readLine()) != null) {
System.out.println("Input "+line);
}
Is there anything wrong with this code or any idea how can I find the owner of current process using Java?
First thing, I think System.getProperty("user.name") should work for that
Second thing, the reason your code is not returning anything is because the command is whoami with NO SPACES so your exec line should be (assuming you are running on windows through cygwin or on a **nix based system)
Process p = Runtime.getRuntime().exec("whoami");

Categories