0

I have a java restful service method which executes a myscript.sh using processBuilder. My script takes one input (example - myscript.sh /path/to-a/folder). Inside the script something like this

-> execute a command which is multithreaded i.e parallel processing
-> echo "my message"

Now when call my script from a linux command line it executes fine. First all the threads running finishes and then some text output from threaded command execution shown on terminal and then echo my message is shown.

But when I call the same script from java using processBuilder, the last echo message comes immidiately and execution ends.

Following the way I call my script from java

ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash","/path/to/myscript.sh","/path/to/folder/data");
Process proc = processBuilder.start();
StringBuffer output = new StringBuffer();
        BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        String line = "";
        while((line = reader.readLine()) != null){
            output.append(line + "\n");
        }

        System.out.println("### " + output);

I don't know whats happening, how to debug also. Can someone enlighten me on how to get the same behaviour from shell script when run from terminal or from java processBuilder?

Surjya Narayana Padhi
  • 7,741
  • 25
  • 81
  • 130
  • Can you also post what your script is doing? the above looks fine barring some exception handling. – Aniruddh Dikhit Nov 16 '16 at 09:18
  • Are you running any executable in background inside the shell script? If so, your script may have returned before it finishes ... and thus killing the executable (or leaving it orphaned). – blackpen Nov 16 '16 at 09:27
  • Do you want the script to block until its parallel work is done? Or is it Java code that is not waiting for the script to finish? – alok Nov 16 '16 at 10:43

2 Answers2

1

Use ProcessBuilder.redirectErrorStream(boolean redirectErrorStream) with argument true to merge the errors into output. Alternatively, you could also use the shell command syntax cmd 2>&1 to merge the error with output.

These are some of the cases why you may be immediately getting the output of the last echo statement (instead of the script taking time to run and return proper results):

  • Missing environment variables
  • The launched bash needs to source .bashrc or some such recource file
  • The launched bash may not be running in right directory (you can set this in ProcessBuilder)
  • The launched bash may not be finding some script/executable in its PATH
  • The launched bash may not be finding proper libraries in the path for any of the executables

Once you merge error, you would be able to debug and see the errors for yourself.

blackpen
  • 2,339
  • 13
  • 15
0

In your context, separate processes may be spawned in two ways:

1) Bash

/path/to/executables/executable &

This will spawn a new executable executable and you need to wait for it to finish.
Here's an answer that will help you.

2) Java

Process exec = Runtime.getRuntime().exec(command);
status = exec.waitFor();

Essentially, you need to wait for the process to end before you start reading its std/err streams.
If I understand the problem correctly, adding just this line to your code should suffice: status = exec.waitFor() (Before you obtain the streams)

Here's the JavaDoc for Process.waitFor() :

Causes the current thread to wait, if necessary, until the process represented by this Process object has terminated. This method returns immediately if the subprocess has already terminated. If the subprocess has not yet terminated, the calling thread will be blocked until the subprocess exits.

Returns: the exit value of the subprocess represented by this Process object. By convention, the value 0 indicates normal termination. Throws: InterruptedException - if the current thread is interrupted by another thread while it is waiting, then the wait is ended and an InterruptedException is thrown

Community
  • 1
  • 1
alok
  • 502
  • 3
  • 15