1

I need to run shell scripts or system commands using process builder. In some cases the command will ask for user input. For example, I have a java program "TestScanner" that takes an integer from command line and print it out. If I run it directly in terminal, something like

$bash -c "java TestScanner"
Enter a number:3
Number entered:3
$

The program displayed message for input. Then I input "3", then it printed out the result and the program terminated.

Now I need to run the command

bash -c "java TestScanner"

from a java process builder. Code is

// cmdList has 3 elements: bash, -c, java TestScanner
ProcessBuilder pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true);
pb.directory(new File(workDir));
Process p = pb.start();
InputStream in = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = br.readLine()) != null)
{
    System.out.println("Line: " + line);
}

When I run the above code snippet, it just hang there. I even could not see the message "Enter a number". I am not sure whether this is because p.getOutputStream() is waiting? How to detect that an input is requested by the program? I tried code snippet from here Java Process with Input/Output Stream and it does not work in my case. Thanks

Community
  • 1
  • 1
CMZS
  • 601
  • 6
  • 21
  • 1
    Something like [this](http://stackoverflow.com/questions/18838904/java-program-that-runs-commands-with-linux-terminal/18839348#18839348) or [this](http://stackoverflow.com/questions/32343355/java-linux-terminal-in-jpanel/32343778#32343778) – MadProgrammer Mar 04 '16 at 22:04
  • That's very helpful. Thanks – CMZS Mar 10 '16 at 19:14

3 Answers3

2

Let's say you have a process p, you can get the InputStream to read what the process prints, just as you have done. But in case you want some input to be provided you have to make use of OutputStream of the process.

Process p=pb.start();
OutputStream os = p.getOutputStream();
PrintWriter writer=new PrintWriter(os);
writer.write("1\n"); //'\n' to simulate enter key

And in your case it seems like the line "Enter a number:" does not have a line break or '\n' char at the end so technically it is not a line. So using buffered reader read line will not be helpful. This may be a problem for the program hanging there for long.

Tharun
  • 311
  • 2
  • 14
1

After studying the nice tutorials by MadProgrammer (see his comments), I see what happened in my problem.

InputStream in = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = null;
while ((line = br.readLine()) != null) {...}

Here BufferedReader is trying to read a line (terminated by EOL), but the InputStream returned by the process object never reached the EOL before user input something to the OutputStream and hit Enter. That's why the prompt message "Enter a number" didn't show up. Change the read method to

is.read() != -1

in the while loop will display the prompt message. Then the issue is how to detect the user input. When user input something and hit enter, data was in the OutputStream's buffer. What we need to implement is the logic to "sense" that something was in the OutputStream and it needs to be written and flush. In my case I have a SWT Text for the user to input data, so I added a SWT.DefaultSelection event listener to the Text control to respond to the keyboard input. And then I saw the correct program output.

CMZS
  • 601
  • 6
  • 21
0

Do you have to use a ProcessBuilder? The same could be achieved using java.io.Console class.

Name Name
  • 175
  • 1
  • 2
  • 11