我编写了这段简单的代码来测试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中工作(返回我系统的python版本),但在我的macbook中相同的代码返回行尾,所以基本上是空的。?这需要根据操作系统进行进一步配置?为什么会这样?
1条答案
按热度按时间bsxbgnwa1#
您得到了什么错误代码?
有(至少)两种解释;该错误代码将指示它是哪一个。
您没有运行python,也没有运行“错误”的python
这意味着您将获得某种类型的错误代码或异常。
原因可能是路径问题。
跑步
python
,就像那样-就像在中一样,根本没有路径信息,名义上是必须被破坏的:这不是你的操作系统的工作方式,它不知道如何处理这个路径。将这样一个命令解释为“哦,实际上,遍历
$PATH
环境变量,并将该路径粘贴在该名称前面,查看是否在其中找到可执行文件。如果你这样做了,运行它并停止)。java基本上不参与任何Bashism。但是,在一些奇怪的地方,它确实做到了——当您使用单字符串版本的
new ProcessBuilder
),这是一个shellism,它确实尝试进行基本的路径查找,但这只是它的结束。不行*
解包,在windows上是操作系统级的事情,但在posix系统上是一种空壳主义。我强烈建议您避免java的基本外壳主义。它是不可靠的,并且高度特定于操作系统。
所以:始终显式地传递参数(很好,您正在这样做),始终使用
ProcessBuilder
(很好,你正在这么做),永远不要使用相对路径(这就是你出错的地方)。它将进入错误流
操作系统上的进程通常连接到3个管道,而不是2个。有“标准输入”、“标准输出”和“标准错误”。您自己的java进程将这些公开为
System.out
,in
,及err
.特别是在linux中,将标准从某个进程重定向到某个文件或另一个进程是很常见的。
这意味着标准err自然具有它倾向于向控制台发出的属性,即使您正在重定向内容。换句话说,“标准输出”和“标准错误”这两个术语在posix上是非常愚蠢的名称。更好的命名应该是“标准流程输出”和“标准流程消息”。
要求python打印其版本有点不确定。字符串“Python V3.0.1”或WHATNOT当然不是一个错误,但是如果人们认为这是“进程的输出”,那就有点可疑了。Python工具的作者很可能会把更多的信息“我应该打印给你”,即使你正在重定向的东西。
因此,我的猜测是,这个版本正在走向标准错误。
您可以通过两种方式解决此问题:也可以从标准err读取,或者使用process builder的功能:您可以要求它将标准输出和标准err捆绑到单个流中(
.redirectErrorStream(true)
).如果这个解释是正确的,我希望退出代码是0。