【问题标题】:Java not getting output of shell-launched programJava没有得到shell启动程序的输出
【发布时间】:2021-11-23 09:33:59
【问题描述】:

我有一个用 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 $1 | 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());
    }
  }
}

【问题讨论】:

    标签: java bash shell process


    【解决方案1】:

    如果您的 MyJarProgram.jar 将其输出打印到 stderr,它将出现在您的屏幕上,但不会被管道捕获到 xargs(并且由于您正在使用 p.getInputStream() 阅读而被丢弃,该 p.getInputStream() 专门读取 stdout )。要么改变你的程序打印到标准输出;或将其标准错误重定向到标准输出,如下所示:

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

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

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

    【讨论】:

    • 感谢您的回答!但是我的 JAR 程序已经在标准输出上打印了输出。但这不是问题,因为在终端上脚本和 JAR 程序都能完美运行(它们在终端上打印正确的结果)。所以我会说问题在于输入流读取没有得到脚本输出。
    【解决方案2】:

    我自己解决了这个问题! 首先我错过了我可以将 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();
    

    这样一切正常。

    【讨论】:

      猜你喜欢
      • 2018-08-13
      • 2021-03-11
      • 2023-04-09
      • 1970-01-01
      • 2014-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多