Reputation: 1852
I am writing a program to read commands from a file, execute them and print the result of each command.
This is what i have: import java.io.*;
public class StatsGenerator {
public static void main(String [] args) throws IOException {
ProcessBuilder builder = new ProcessBuilder( "/bin/bash" );
Process p = builder.start();
// get output from the process
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader processOutput = new BufferedReader(isr);
InputStream errorStream = p.getErrorStream();
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
BufferedReader processErrorOutput = new BufferedReader(inputStreamReader);
// get input to the process
BufferedWriter processInput = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
// get commands to execute
File f = new File("commands.txt");
FileReader fileReader = new FileReader(f);
BufferedReader commandsReader = new BufferedReader(fileReader);
String command, output;
while((command = commandsReader.readLine()) != null) {
System.out.printf("Output of running %s is:\n", command);
processInput.write(command);
processInput.newLine();
processInput.flush();
while (processErrorOutput.ready() && (output = processErrorOutput.readLine()) != null) {
System.out.println(output);
}
while ((output = processOutput.readLine()) != null) {
System.out.println(output);
}
}
// close process
processInput.write("exit");
processInput.newLine();
processInput.flush();
// close streams
commandsReader.close();
processErrorOutput.close();
processInput.close();
processOutput.close();
}
}
commands.txt
java Solve problems/problem01.txt
java Solve problems/problem02.txt
java Solve problems/problem03.txt
However this runs and outputs the result of the first command but gets stuck on the second one ... ( and I know that Solve can solve the second one )
What am i doing wrong ?
EDIT1:
Turns out the "Exception in thread 'main'" error from the picture is due to me pressing the CMD+C. This still does not explain why it stops outputting.
Upvotes: 2
Views: 3436
Reputation: 140
And yet better is to run error and stream reading in separate threads in order to provide make program able to do something else, terminate process for instance
Upvotes: 0
Reputation: 31300
The problem I see here is that you create a process running a shell (OK), get hold of the input and output streams of that process (OK), read a command from the file (OK) and feed it to the process (OK). Then you keep reading output lines, which succeeds while the the first Java program executes and produces output.
Then the
while ((output = processOutput.readLine()) != null) { ...
blocks as there is neither another line nor EOF.
You can fix this by spawning a thread to read and print processOutput.
Another option (which I'd very much prefer) is to create one process per command. As far as I can see you don't even need a shell: you could execute java SolveProblem ...
right away. (Unices have been built for efficient subprocess creation, and don't think the shell does it differently, so there's no additional overhead to be afraid of.)
Just two hints for calling java without a shell: make sure to use the full path name and split the command line into tokens.
Edit And here it is, just using a String[] instead of your text file containing commands.
for( String cmd: new String[]{ "java Y aaa", "java Y bbb","java Y ccc" } ){
String[] toks = cmd.split( "\\s" );
ProcessBuilder builder = new ProcessBuilder( toks );
Process p = builder.start();
// get output from the process
InputStream is = p.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader processOutput = new BufferedReader(isr);
InputStream errorStream = p.getErrorStream();
InputStreamReader inputStreamReader = new InputStreamReader(errorStream);
BufferedReader processErrorOutput = new BufferedReader(inputStreamReader);
System.out.println("Executing " + cmd);
String output;
while( processErrorOutput.ready() &&
(output = processErrorOutput.readLine()) != null) {
System.out.println(output);
}
while ((output = processOutput.readLine()) != null) {
System.out.println(output);
}
processErrorOutput.close();
processOutput.close();
}
Output (silly Y prints argument three times):
Executing java Y aaa 1aaa 2aaa 3aaa Executing java Y bbb 1bbb 2bbb 3bbb Executing java Y ccc 1ccc 2ccc 3ccc
Another Edit If a marker line is inserted into the process output and the read loop checks the lines for this marker, the program can be used as it is (except for some corrections for closing processInput):
processInput.write(command + "; echo xxxEOFxxx");
//...
while ((output = processOutput.readLine()) != null
&& ! "xxxEOFxxx".equals(output)) {
System.out.println(output);
}
Although I dislike the use of "magic strings" in this way it may be permissible here as you know the set of output lines of program Solve
.
Upvotes: 2