2

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 )

enter image description here

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.

1
  • Why are you using a command interpreter to start with? Commented Nov 16, 2015 at 18:35

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

10 Comments

"read a command from the file (OK)" <-- uh? Given the invocation of bash, it won't be able to interpret that command file in the least....
The way I imagined it was that I open bash, execute the first command, read the output of it, execute the second one, read the output of it ... and so on, Since while ((output = processOutput.readLine()) != null) { blocks I was expecting it to continue working once the Process fills the processOutput reader with the new output. The reason I am doing this is because i need the outputs of each commands in one place afterwards.
I know what you had in mind, but the Java program doesn't sense the end of the output of the first program invocation. - What I have proposed will still let you handle the output any way you want. Even better, because with separate processes you will have EOF after each execution.
@mp3por Now I've added a demo for my simple proposal. Your code was good, just the blocking read...
@laune for one, arguments spanning more than one space; second, the fact that if you run a bona fide shell script, then state may be lost. Among other things.
|
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.