ProcessBuilder 的输入流为空,具体取决于 OS

ProcessBuilder's inputstream empty depending of OS

我编写了这段简单的代码来测试 ProcessBuilder:

@SpringBootApplication
public class TerminalDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(TerminalDemoApplication.class, args);
        try {
            System.out.println("hello");
            Process process = new ProcessBuilder("python", "--version").start();
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            int exitCode = process.waitFor();
            System.out.println("\nExited with error code : " + exitCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

}

它在 Windows(我系统的 returns python 版本)中工作,但在我的 macbook returns 行尾有相同的代码,所以基本上是空的。 ¿这需要根据 OS 进一步配置吗? ¿为什么会这样?

您收到什么错误代码?

有(至少)两种解释;该错误代码将指示它是哪一个。

你不是 运行宁 python,也不是 运行宁 'the wrong' python

这意味着您收到了某种错误代码或异常。

这可能是路径问题。

运行 python,就像那样 - 根本没有路径信息,名义上必然被破坏:这不是你的 OS 的工作方式,它不知道如何处理此路径。

将这样的命令解释为“哦,实际上,遍历 $PATH 环境变量,并将该路径粘贴在此名称前面,查看是否在那里找到可执行文件。如果你这样做了,运行 那并停止)。

Java 基本上不参与任何 bashisms。但是,在一些奇怪的地方,它确实如此——当你使用 new ProcessBuilder 的单字符串版本时,它会尝试进行基本的 space 拆分,这是一种 shellism,并且它确实尝试进行基本的 PATH 查找,但这就是它结束的地方。它不会 * 解包,这在 windows 上是 OS 级别的事情,但在 posix 系统上是 shellism。

我强烈地,强烈地建议您避免java的基本shell主义。它不可靠且高度 OS 特定。

所以:始终显式传递参数(很好,你正在这样做),始终使用 ProcessBuilder(很好,你正在这样做),永远不要使用相对路径(那是你出错的地方) ).

它将转到错误流

OSes 上的

进程通常连接到 3 个管道,而不是 2 个。有 'standard in'、'standard out' 和'standard err'。您自己的 java 进程将这些公开为 System.outinerr

特别是在 linux 中,将标准从某个进程重定向到文件或另一个进程是很常见的。

这意味着标准 err 自然地具有 属性 它倾向于发送到控制台,即使 你正在重定向东西。换句话说,术语 'standard out' 和 'standard err' 是 真正愚蠢的名字 在 posix 上。更好的命名方式是 'standard process output' 和 'standard process messages'.

要求 python 打印其版本有点悬而未决。字符串“Python v3.0.1”或诸如此类的东西肯定不是错误,但如果将其视为 'the output of the process' 就有点可疑了。 python 工具的作者很可能认为它更多的是“我应该打印给你的一些信息,即使你正在重定向东西。

因此,我的猜测是这个版本正在转向标准错误。

您可以通过两种方式解决此问题:也可以从标准错误中读取,或者使用流程构建器的功能:您可以要求它将标准输出和标准错误捆绑到一个流中(.redirectErrorStream(true) ).

如果此解释正确,我希望退出代码为 0。