3

我试图让我的 Java 程序与 Linux bash 交互,但出现了问题。我有一个简单的可执行文件prog,它从中读取一个整数stdin并输出它的平方。执行

echo 5 | ./prog

从 bash 本身打印正确答案但正在25运行stdout

import java.io.*;

public class Main {
    public static void main(String[] args) throws InterruptedException, IOException {
        Runtime run = Runtime.getRuntime();
        Process proc = run.exec("echo 5 | ./prog");
        proc.waitFor();
        BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        while(br.ready())
            System.out.println(br.readLine());
    }
}

居然给了5 | ./prog。解决办法是什么?

4

1 回答 1

12

Javaexec不能运行这样的 shell 命令。如果要运行shell命令,需要显式调用shell;例如

Process proc = run.exec(new String[]{"/bin/sh", "-c", "echo 5 | ./prog"});

有关 Java 对此做了什么的更多详细信息,请阅读 和 的exec(String)javadocs exec(String[])。请注意,这些是“便捷方法”,您需要遵循底层方法的链接链才能完全理解 javadoc 所说的内容。

如果您想了解更多有关 Java 如何处理此问题的详细信息,请参阅源代码...

如果你想深入了解为什么 Java处理 shell 语法本身,你可能需要深入了解 UNIX/Linux 系统的架构和哲学,以及应用程序、操作系统和命令 shell 之间的关注点分离. 请注意,有无数不同的shell,每个都有(可能)不同的引用规则、参数拆分、重定向、管道等。大多数流行的 shell 都是相似的,但这就是事情的发展方式。

解决方案说明:

  • 手动拆分命令的原因是exec(String)不会正确地将命令拆分为单个命令和参数。它不能。这是一个管道 中有两个命令的示例。

  • 使用“sh”的原因是……嗯……你需要一个shell来解析和处理shell命令行。Java 的exec命令不支持 shell 语法……正如 javadoc 解释的那样。

  • “-c”选项的用途由“man sh”解释。基本上,sh -c "a b c"意思是“使用'sh'来运行命令行'ab c'”。

FWIW,在技术上完全可以在 Java 中构建和运行管道(即不依赖外部 shell),但通常不值得付出努力。您已经通过运行外部命令引入了平台依赖关系,因此特定 shell 命令和语法形式的额外依赖关系不会使事情变得更糟。

于 2013-08-25T00:42:17.367 回答