Java exec()不返回管道连接命令的预期结果

时间:2010-01-18 20:20:15

标签: java linux bash command-line awk

我正在调用通过管道连接的命令行程序。所有这些都可以在Linux上运行。

我的方法:

protected String execCommand(String command) throws IOException {
    String line = null;
    if (command.length() > 0) {
        Process child = Runtime.getRuntime().exec(command);
        InputStream lsOut = child.getInputStream();
        InputStreamReader r = new InputStreamReader(lsOut);
        BufferedReader in = new BufferedReader(r);

        String readline = null;
        while ((readline = in.readLine()) != null) {
            line = line + readline;
        }
    }

    return line;
}

如果我正在调用一些 cat文件| grep asd ,我得到了预期的结果。但并非所有命令都能正常工作。例如:

cat /proc/cpuinfo | wc -l

或者这个:

cat /proc/cpuinfo | grep "model name" | head -n 1 | awk -F":" '{print substr($2, 2, length($2))}

该方法将返回null。我猜这个问题取决于输出格式化命令,如 head tail wc 等。我如何解决这个问题并得到输出的最终结果?

6 个答案:

答案 0 :(得分:8)

管道(如重定向或>)是shell的一个功能,因此直接从Java执行将不起作用。您需要执行以下操作:

/bin/sh -c "your | piped | commands | here"

使用-c(引号)后指定的命令行(包括管道)执行shell进程。

另请注意,您必须同时使用stdoutstderr ,否则您的衍生进程将阻止等待您的进程使用输出(或错误)。更多信息here

答案 1 :(得分:2)

使用Runtime.exec的每个人都应该阅读this

答案 2 :(得分:2)

仍未找到使用Runtime.exec执行管道命令的正确解决方案,但找到了解决方法。我只是编写这些脚本来分隔bash文件。然后Runtime.exec调用这些bash脚本并获得预期的结果。

答案 3 :(得分:1)

同样检查the error stream of the Process可能是个好主意。

答案 4 :(得分:0)

快速而肮脏的事情将是:

command = "/bin/sh -c '" + command.replaceAll("'", "'\''") + "'"

通常情况下,你必须注意shell注入(即有人将"; rm -rf /;"偷偷带入命令中)。但是,如果可以从其他一些用户输入提供部分命令,那只是一个问题。

缓慢而痛苦的方法是用Java自己做Bash管道。如果你走这条路,你会发现Process.exec无法直接获得的所有wonderful things that Bash gives you(管道,重定向,复合命令,变量扩展,算术评估......)。

  1. 解析|个字符的命令。请务必留意||和引用的字符串。
  2. 为每个管道命令生成一个新的Process
  3. 创建Thread来读取一个命令的输出并将其写入下一个命令的输入。

答案 5 :(得分:0)

可能有点太晚了但是对于寻找解决方案的其他人来说,试试这个...

String[] cmd = {
                        "/bin/sh",
                        "-c",
                        "cat /proc/cpuinfo | wc -l"
                    };

Process process = Runtime.getRuntime().exec(cmd);

一切顺利......