【问题标题】:Java getRuntime ExecJava getRuntime 执行
【发布时间】:2015-03-03 18:24:54
【问题描述】:

在 Java 1.8 上调用 p = Runtime.getRuntime().exec(command)。 该命令调用 bash 脚本如下:

#!/bin/bash
args=("$@")
cat /home/user/Downloads/bigtext.txt | grep ${args[0]}

上面的 bash 脚本在命令行调用时可以正常工作。当使用 exec() 在我的 Java 应用程序中调用时,我没有得到任何 CAT 输出。它似乎没有通过 p.waitFor();我哪里错了?

如果我直接运行诸如“ls -alF”之类的命令,一切都会按预期工作。

$ java -version java version "1.8.0_31" Java(TM) SE Runtime Environment (build 1.8.0_31-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.31-b07, mixed mode)


String tmp = "/home/user/search "+input;        
System.out.println(tmp); //  /home/user/search sometextarg
String woa = executeCommand(tmp);


private String executeCommand(String command) {     
        StringBuilder output = new StringBuilder();
                BufferedReader reader = null;
        Process p;
        try {
            p = Runtime.getRuntime().exec(command);
            p.waitFor();

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

            String line = "";

            while ((line = reader.readLine())!= null) {
                output.append(line + "\n");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return output.toString();
    }

【问题讨论】:

  • bigtext.txt 有多大?你在抱怨什么?
  • 它的 136 Mb 文本文件

标签: java exec runtime.exec


【解决方案1】:

您的 Java 进程和您的脚本在等待对方时处于死锁状态:您正在等待进程退出,进程正在等待您读取输出。

它恰好适用于ls -alF 和其他输出较小的命令,因为它们都适合管道的缓冲区(我的系统上为 64kib)。

只需将 p.waitFor() 移到 while 循环下方,您就会有更多的运气:

private String executeCommand(String command) {     
    StringBuilder output = new StringBuilder();
            BufferedReader reader = null;
    Process p;
    try {
        p = Runtime.getRuntime().exec(command);
        reader = new BufferedReader(new InputStreamReader(p.getInputStream()));

        String line = "";
        while ((line = reader.readLine())!= null) {
            output.append(line + "\n");
        }
        p.waitFor();

    } catch (Exception e) {
        e.printStackTrace();
    }
    return output.toString();
}

如果您还希望它能够正确处理包含空格和某些其他字符的值,您必须:

  1. 在您的脚本中引用"${args[0]}"
  2. 重写您的executeCommand 以使用Runtime.exec(String[]) 而不是Runtime.exec(String)

【讨论】:

  • 等你看输出你能解释一下吗?
  • @SotiriosDelimanolis 您的脚本写入数据的速度比 Java 程序读取数据的速度要快得多。但是,这不会cause a mess 因为不是尽可能快地推送数据,完全压倒Java 程序,脚本将1. 写入一大块数据,2. 等待它被读取。 3. 根据需要重复(这就是管道的工作方式)。在您的情况下,脚本停留在第 2 步,因为您根本没有从管道读取,而是等待程序退出。
  • 我希望您澄清的部分是管道的工作原理。生成的进程不应等待 Java(或任何其他进程)从其标准输出中读取。
  • @SotiriosDelimanolis 管道的缓冲区有限。当缓冲区已满时,进程在清空之前无法写入。当缓冲区为空时,进程在填满之前无法读取。在您概述的用例中,这绝对是您想要的。如果您有一个完全不同的用例,例如对工业机械控制器有严格的延迟要求,请发布一个单独的问题。
  • 所以你是说问题在于cat /home/user/Downloads/bigtext.txt | grep ${args[0]} livelocking,帽子grep 不能继续,因为java 进程没有读取它的输出?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 2017-11-17
  • 2012-11-08
  • 1970-01-01
相关资源
最近更新 更多