java - ProcessBuilder 的输入流为空,具体取决于操作系统
问题描述
我编写了这段简单的代码来测试 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 中的相同代码返回行尾,所以基本上是空的。¿ 这需要根据操作系统进行进一步配置吗?¿为什么会这样?
解决方案
你得到什么错误代码?
(至少)有两种解释;该错误代码将指示它是哪一个。
你没有运行 python,或者运行“错误的”python
这意味着您收到某种错误代码或异常。
造成这种情况的可能原因是路径问题。
Runningpython
就像那样 - 就像根本没有路径信息一样,名义上必然会被破坏:这不是你的操作系统的工作方式,它不知道如何处理这条路径。
将这样的命令解释为“哦,实际上,遍历$PATH
环境变量中列出的每个条目,并将该路径粘贴在该名称前面,看看你是否在那里找到一个可执行文件。如果你这样做了,运行它并停止)。
Java 大多不参与任何 bashisms。但是,在一些奇怪的地方,它确实 - 当你使用 ) 的单字符串版本时,它会尝试进行基本的空间分割new ProcessBuilder
,这是一种 shellism,并且它确实尝试进行基本的 PATH 查找,但这就是它结束的地方. 它不会进行*
解包,这在 Windows 上是操作系统级别的东西,但在 posix 系统上是一种 shellism。
我强烈建议您避免使用 java 的基本 shellisms。它不可靠且高度特定于操作系统。
所以:总是明确地传递参数(很好,你正在这样做),总是使用ProcessBuilder
(很好,你正在这样做),永远不要使用相对路径(那是你出错的地方)。
而是转到错误流
操作系统上的进程通常连接到3 个管道,而不是 2 个。有“标准输入”、“标准输出”和“标准错误”。您自己的 java 进程将这些公开为System.out
,in
和err
.
特别是在 linux 中,将标准从某个进程重定向到一个文件或另一个进程是很常见的。
这意味着标准错误自然具有它倾向于向控制台发出的属性,即使您正在重定向事物。换句话说,术语“标准输出”和“标准错误”在 posix 上是非常愚蠢的名称。更好的命名是“标准流程输出”和“标准流程消息”。
要求 python 打印它的版本有点悬而未决。字符串“Python v3.0.1”或诸如此类的东西当然不是错误,但是如果将其视为“过程的输出”,那就有点可疑了。python 工具的作者很可能认为它更像是“我应该打印给你的一些信息,即使你正在重定向东西。
因此,我的猜测是这个版本正在走向标准错误。
您可以通过两种方式解决此问题:也可以从标准错误中读取,或者使用流程构建器的功能:您可以要求它将标准输出和标准错误捆绑到单个流中(.redirectErrorStream(true)
)。
如果这个解释是正确的,我希望退出代码为 0。
推荐阅读
- python - urllib3 重试不适用于请求
- ruby-on-rails - 使用 Net :: HTTP 发出请求返回状态 200 但无法正常工作
- javascript - 动画画布背景闪烁?
- ios - SwiftUI Form 和 StackNavigationViewStyle 狂奔
- javascript - Amcharts4: 'legendSettings' 'itemValueText' 检查空值或未定义值
- angular - *ngIf 不会打开模板
- firebase - 如何在颤动中自动登录现有用户
- javascript - 在我们的分隔符的每一秒出现一次时使用 str.split()
- angularjs - AngularJS 的两种不同的 HTML
- r - 导入大量文本文件并删除重复行