1

I have a java app that runs a bash file and inside the bash file i have a code to run another java app and it doesn't seem to work.I come from c++ where this is a very easy task but i'm not really experienced in java. So, here's my code:

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class start {

public void executeScript(){
    try{
        ProcessBuilder pb = new ProcessBuilder("/root/Desktop/chat/script.sh");
        Process p = pb.start();
        p.waitFor();
        System.out.println("Script executed..");
    }catch(Exception e){
        e.printStackTrace();
        }

}

public static void main(String[] args) {
    start st = new start();
    System.out.println("I'm main..");
    st.executeScript();
}

}

Here's my bash file:

#!/bin/bash
echo "bash started"
java Client ip_address
echo "bash finished"

Here's the result of this code:

I'm main.. Script executed..

I know "Script executed.." shouldn't print because the java file i'm trying to run from the bash file is an infinite loop.

Note: If i run the bash file separately in the terminal i get an infinite loop which is the intended result and this is why i know that my mistake is from this file.

I hope I made myself clear and if not please ask for more information. Thank you.

John123
  • 122
  • 1
  • 2
  • 11
  • Add some `echo` commands to the bash script so you see how far it gets. – Arndt Jonasson Mar 29 '18 at 14:24
  • @ArndtJonasson I tried that before and the echos are not displayed in the terminal. – John123 Mar 29 '18 at 14:27
  • I use Runtime.getRuntime().exec to create processes, maybe that will help. Also, the echos should be captured in the input stream of the process (see https://stackoverflow.com/questions/15801069/printing-a-java-inputstream-from-a-process?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa for how to print out the results) – V3V Mar 29 '18 at 14:43

4 Answers4

5

Another way of doing would be to use Runtime.getRuntime(). Something like this

  public void executeScript() throws IOException, InterruptedException {
    Process p = Runtime.getRuntime().exec("sh /root/Desktop/chat/script.sh");
    p.waitFor();

    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
    BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));


    String line = "";
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }

    line = "";
    while ((line = errorReader.readLine()) != null) {
        System.out.println(line);
    }
}
Jeffin Manuel
  • 542
  • 1
  • 6
  • 18
  • I used this and now the echo statements are printed but still i can't run the file `Client`! – John123 Mar 29 '18 at 14:56
  • @John123 I have made a minor edit which would enable you to also get the error result. I guess is, "Client" is not in the right location. Just do a "pwd" and make sure it is in the right path. – Jeffin Manuel Mar 29 '18 at 15:17
  • This is the output now: `I'm main.. bash started bash finished Error: Could not find or load main class Client` This is weird because as i said before if i run the client separately it works normally! – John123 Mar 29 '18 at 15:22
1

With the above test you can not guaranty that whether it is running or not. Because clearly you told that your are running a infinite loop inside your second java application. Now my advise would be to put some System.out.println statement inside that infinite loop and use below java code to execute your shell script. Here in the output.txt file you can see the output from your shell script as well as java program and you will know whether application executed successfully or not. Also put some echo statement inside your shell script as well.

 String[] command ={"/root/Desktop/chat/script.sh", "command line param if any"};
    ProcessBuilder pb = new ProcessBuilder(command);

    pb.redirectOutput(new File("/tmp/output.txt"));
    String result;
    String overall="";
    try {
        Process p = pb.start();
        p.waitFor();
        BufferedReader br = new BufferedReader(
                new InputStreamReader(p.getInputStream()));
            while ((result = br.readLine()) != null){
                overall = overall + "\n" + result;
            }
            p.destroy();
            System.out.println(result);

    } catch (Exception e) {
        e.printStackTrace();
    }
Abhijit Pritam Dutta
  • 5,521
  • 2
  • 11
  • 17
  • I added an `getErrorStream()` and i got this output in the file: `I'm main.. bash started bash finished Error: Could not find or load main class Client` – John123 Mar 29 '18 at 15:30
  • Your problem is with java class path. Inside the shell script set the class path before executing the java application. – Abhijit Pritam Dutta Mar 29 '18 at 15:37
0

You can also use my small library called jaxec:

import com.yegor256.Jaxec;
String stdout = new Jaxec("script.sh")
    .withHome("/home/me") // run it in this directory
    .withRedirect(false) // don't redirect STDERR to STDOUT
    .exec();

Jaxec class will not only execute the shell command, but will also send its output to Slf4j log, will wait for its completion, redirect stderr to stdout, and make sure an exception is raised if the exit code is not equal to zero.

yegor256
  • 102,010
  • 123
  • 446
  • 597
-1

if you start a process like you wrote Process p = pb.start(); it will make(we usually say fork) one more process from the java process.

  1. for example, java is running as a process 'A'

  2. and if the process 'A' starts another process 'B'

  3. then those are running at the same time.

    (in your case, A is 'JAVA' and B is 'Shell')

so, it will be 2. and the 2 processes are running in the same time (parallely), so you will get two of those results at the same time.

Community
  • 1
  • 1
  • But i guess this is why i used `p.waitFor() ;` because now process `A` will not start until process `B` is finished? – John123 Mar 29 '18 at 14:58