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

6

我将调用通过管道连接的命令行程序。这在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 file | 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。我猜测这个问题取决于输出格式化命令,比如headtailwc等。我该如何解决这个问题并获取输出的最终结果?


@Dennis - 确实。发现得好! - Brian Agnew
@Bobby,我已经尝试过了,这并没有帮助。 - Pawka
6个回答

8

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

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

这个函数使用在-c后指定的命令行(包括管道)来执行一个shell进程。

同时需要注意,你必须同时处理stdoutstderr,否则你所派生的进程将会被阻塞,等待你的进程去消耗输出(或错误)。更多信息请参考这里


2

Everyone who uses Runtime.exec should read this.


1

最快捷的方法是:

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

通常,您需要注意Shell注入(即有人将"; rm -rf /;"偷偷插入命令)。但是,只有在命令的一部分可以从其他用户输入中提供时才会出现此问题。

缓慢而痛苦的方法是在Java中自己执行Bash管道。如果您选择这条路,您将发现所有Bash给您提供的美妙之处,这些功能不直接可用于Process.exec(管道、重定向、复合命令、变量扩展、算术计算等)。

  1. 解析带有|字符的命令。一定要注意||和带引号的字符串。
  2. 为每个管道命令生成新的Process
  3. 创建Thread,读取一个命令的输出并将其写入下一个命令的输入。

1

1

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


这是我通过谷歌找到的唯一解决方案。你不能接受自己的答案吗?不管怎样,非常感谢。 - user168237

0

可能有点晚了,但对于其他正在寻找解决方案的人,请尝试这个...

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

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

祝一切顺利。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接