Home > OS >  Java not getting output of shell-launched program
Java not getting output of shell-launched program

Time:10-03

I have a small HTTP server written in Java. When it receive a HTTP request in the form "localhost:port/something" it calls a shell script that takes as only arg "something".

Then the shell script inside himself calls another .jar Java program that simply takes "something" as arg, reverse the String and then prints it out. The shell script takes the output of the JAR program and writes it out, so that the server can receive back this output ("gnihtemos") and send it to the browser.

The problem is that everything works fine but only if inside the shell script I use directly the "echo" command. So for example if my shell script is:

#!/bin/bash
echo printthisout

the server receives "printthisout" as output from the script and then sends it back to the browser without any problem.

But if I change the script to:

#!/bin/bash
java -jar MyJarProgram.jar $1 | xargs echo

No output arrives to the server. But if I run the script from terminal, it works fine. And it means that also the JAR program is working. UPDATE: On the opposite,if I call directly the JAR program from the web server (skipping the shell script) it neither works. The output seems to be empty. So the problem seems to be making the web server catching the stdout from the JAR program. I tried everything: sleep, wait, waitFor() method, calling the subprocess using exec(), etc., but nothing seems to work. I'm pretty sure I'm missing something of very basic, but really have no idea about what.

This is the part of the server that calls the script and gets the output back:

                String result = "";
                try {
                    Runtime r = Runtime.getRuntime();
                    String cmd="/path/to/script/script.sh "   req; //req is the request token, "something" in the example above
                    System.out.println("Command: "   cmd);

                    ProcessBuilder builder = new ProcessBuilder("bash", cmd);
                    Process p = builder.start();
                    
                    BufferedReader in =
                            new BufferedReader(new InputStreamReader(p.getInputStream()));
                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        System.out.println("Input line: "   inputLine);
                        result  = inputLine;
                    }
                    in.close();

                    System.out.println("Result of script: "  result);

                    ps.print("HTTP/1.1 200 OK\r\n");
                    ps.print("Content-Type: text/html\r\n");
                    ps.print("\r\n\r\n");
                    ps.print("<link rel=\"icon\" href=\"data:,\">\r\n");
                    ps.print(result   "\r\n");

                } catch (IOException e) {
                    System.out.println(e);
                }

The problem is that "inputLine" remains empty.

This is the JAR Java program called by the script:

    public static void main(String[] args) {
    if(args.length>0) {
        StringBuilder sb =new StringBuilder(args[0]);
        System.out.println(sb.reverse().toString());
    }
  }
}

CodePudding user response:

If your MyJarProgram.jar prints its output to stderr, it would appear on your screen, but would not be captured by the pipe to xargs (and is being dropped because you're reading with p.getInputStream(), which specifically reads stdout). Either change your program to print to stdout; or redirect its stderr to stdout like this:

#!/bin/bash
java -jar MyJarProgram.jar "$1" 2>&1 | xargs echo

I'd also drop the | xargs echo as the output would be sent back either way -- no need for an extra level of echo processing:

#!/bin/bash
java -jar MyJarProgram.jar "$1" 2>&1

CodePudding user response:

I solved the problem myself! First of all I was missing I can redirect errout of the ProcessBuilder to stdout with:

builder.redirectErrorStream(true);

This gave me a basical debugging solution. From there I discovered that the hidden error was that the Java web server was launching the script in a wrong way. It reported:

"bash: /path/of/script.sh something: File or directory not found"

The problem is that the script has to be called as main command when instancing the ProcessBuilder, and then pass the arg String as string, always in the constructor:

ProcessBuilder builder = new ProcessBuilder("/path/of/script.sh", req); //Where req is the String thas has to be reversed

I also added the Process.waitFor() call after starting the process:

Process p = builder.start();
p.waitFor();

This way everything works well.

  • Related