繁体   English   中英

如何使管道与 Runtime.exec() 一起工作?

[英]How to make pipes work with Runtime.exec()?

考虑以下代码:

String commandf = "ls /etc | grep release";

try {

    // Execute the command and wait for it to complete
    Process child = Runtime.getRuntime().exec(commandf);
    child.waitFor();

    // Print the first 16 bytes of its output
    InputStream i = child.getInputStream();
    byte[] b = new byte[16];
    i.read(b, 0, b.length); 
    System.out.println(new String(b));

} catch (IOException e) {
    e.printStackTrace();
    System.exit(-1);
}

程序的输出是:

/etc:
adduser.co

当然,当我从 shell 运行时,它按预期工作:

poundifdef@parker:~/rabbit_test$ ls /etc | grep release
lsb-release

互联网告诉我,由于管道行为不是跨平台的,在生产 Java 的 Java 工厂工作的聪明人不能保证管道工作。

我怎样才能做到这一点?

我不打算使用 Java 结构而不是grepsed来完成所有的解析,因为如果我想更改语言,我将被迫用该语言重新编写我的解析代码,这完全是不可能的 -走。

调用shell命令时如何让Java进行管道和重定向?

编写脚本,然后执行脚本而不是单独的命令。

管道是外壳的一部分,因此您也可以执行以下操作:

String[] cmd = {
"/bin/sh",
"-c",
"ls /etc | grep release"
};

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

我在 Linux 中遇到了类似的问题,除了它是“ps -ef | grep someprocess”。
至少使用“ls”,你有一个独立于语言(虽然速度较慢)的 Java 替代品。 例如。:

File f = new File("C:\\");
String[] files = f.listFiles(new File("/home/tihamer"));
for (String file : files) {
    if (file.matches(.*some.*)) { System.out.println(file); }
}

使用“ps”有点困难,因为 Java 似乎没有它的 API。

我听说 Sigar 可能会帮助我们: https : //support.hyperic.com/display/SIGAR/Home

然而,最简单的解决方案(如 Kaj 所指出的)是将管道命令作为字符串数组执行。 这是完整的代码:

try {
    String line;
    String[] cmd = { "/bin/sh", "-c", "ps -ef | grep export" };
    Process p = Runtime.getRuntime().exec(cmd);
    BufferedReader in =
            new BufferedReader(new InputStreamReader(p.getInputStream()));
    while ((line = in.readLine()) != null) {
        System.out.println(line); 
    }
    in.close();
} catch (Exception ex) {
    ex.printStackTrace();
}

至于为什么 String 数组可以与管道一起使用,而单个字符串则不能……这是宇宙的奥秘之一(尤其是如果您还没有阅读源代码的话)。 我怀疑这是因为当给 exec 一个字符串时,它首先解析它(以我们不喜欢的方式)。 相反,当给 exec 一个字符串数组时,它只是将它传递给操作系统而不对其进行解析。

实际上,如果我们在忙碌的一天中抽出时间查看源代码(在http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/ Runtime.java#Runtime.exec%28java.lang.String%2Cjava.lang.String[]%2Cjava.io.File%29 ),我们发现这正是正在发生的事情:

public Process  [More ...] exec(String command, String[] envp, File dir) 
          throws IOException {
    if (command.length() == 0)
        throw new IllegalArgumentException("Empty command");
    StringTokenizer st = new StringTokenizer(command);
    String[] cmdarray = new String[st.countTokens()];
    for (int i = 0; st.hasMoreTokens(); i++)
        cmdarray[i] = st.nextToken();
    return exec(cmdarray, envp, dir);
}

创建一个运行时来运行每个进程。 从第一个 Runtime 获取 OutputStream 并将其从第二个 Runtime 复制到 InputStream。

@Kaj 接受的答案适用于 linux。 这是 Windows 的等效项:

String[] cmd = {
"cmd",
"/C",
"dir /B | findstr /R /C:"release""
};
Process p = Runtime.getRuntime().exec(cmd);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM