【问题标题】:Why does my Java code execute bash command incorrectly?为什么我的 Java 代码执行 bash 命令不正确?
【发布时间】:2013-08-27 18:52:47
【问题描述】:

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

echo 5 | ./prog

来自 bash 本身在 stdout 中打印正确答案 25 但正在运行

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。解决办法是什么?

【问题讨论】:

标签: java linux bash pipe


【解决方案1】:

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

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

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

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

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

解法说明:

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

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

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

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

【讨论】:

  • 为什么要把/bin/sh-c分开,或者我在哪里可以找到Runtime.exec(...)工作的详细信息?
  • 我没有看到可以解释 javadoc 中 /bin/sh-c 的问题,你呢?所以,是的,我先看了那里。
  • javadocs 解释了 Java 如何进行参数拆分。您还需要了解在 Linux 中如何处理命令参数(在 shell 和系统调用级别)......以及管道、重定向等的语法是由 shell 而非操作系统实现的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-17
  • 2019-08-04
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多