Java 没有得到 shell 启动程序的输出

Java not getting output of shell-launched program

我有一个用 Java 编写的小型 HTTP 服务器。当它收到“localhost:port/something”形式的 HTTP 请求时,它会调用一个 shell 脚本,该脚本只接受 arg“something”。

然后 shell 脚本自己调用另一个 .jar Java 程序,该程序简单地将“某物”作为 arg,反转字符串,然后将其打印出来。 shell 脚本获取 JAR 程序的输出并将其写出,以便服务器可以接收回该输出(“gnihtemos”)并将其发送到浏览器。

问题是一切正常,但前提是我在 shell 脚本中直接使用“echo”命令。例如,如果我的 shell 脚本是:

#!/bin/bash
echo printthisout

服务器接收“printthisout”作为脚本的输出,然后毫无问题地将其发送回浏览器。

但是如果我将脚本更改为:

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

没有输出到达服务器。 但是如果我 运行 来自终端的脚本,它工作正常。这意味着 JAR 程序也在运行。更新:相反,如果我直接从 Web 服务器调用 JAR 程序(跳过 shell 脚本),它都不起作用。输出似乎是空的。所以问题似乎是让网络服务器从 JAR 程序中捕获标准输出。 我尝试了所有方法:睡眠、等待、waitFor() 方法、使用 exec() 调用子进程等,但似乎没有任何效果。我很确定我错过了一些非常基本的东西,但真的不知道是什么。

这是调用脚本并取回输出的服务器部分:

                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);
                }

问题是“inputLine”仍然是空的。

这是脚本调用的 JAR Java 程序:

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

如果你的 MyJarProgram.jar 将它的输出打印到 stderr,它会出现在你的屏幕上,但不会被 xargs 的管道捕获(并且正在被丢弃,因为你正在阅读 p.getInputStream(),专门读取标准输出)。要么更改您的程序以打印到标准输出;或像这样将其 stderr 重定向到 stdout:

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

我还会删除 | xargs echo,因为输出会以任何一种方式发回——不需要额外级别的 echo 处理:

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

我自己解决了这个问题! 首先我错过了我可以将 ProcessBuilder 的错误重定向到标准输出:

builder.redirectErrorStream(true);

这给了我一个基本的调试解决方案。从那里我发现隐藏的错误是 Java Web 服务器以错误的方式启动脚本。据报道:

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

问题是在实例化 ProcessBuilder 时必须将脚本作为主命令调用,然后将 arg 字符串作为字符串传递,始终在构造函数中:

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

我还在启动进程后添加了Process.waitFor()调用:

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

这样一切都很好。