【发布时间】:2023-03-11 08:08:01
【问题描述】:
我的问题包括一些关于在 Windows 中从 Java 执行子进程时使用“cmd.exe”、“/c”的问题。基本上,我找不到关于何时以及为什么需要它们的很好解释。
我的具体问题:我有一个用于子流程执行的小框架。一种用途是 Java 应用程序,它“管理”由 ProcessBuilders 创建的其他几个 JVM。关键要求之一是当子进程卡住或托管应用程序终止时,它必须能够终止子进程。
问题是,一方面,这样做:
new ProcessBuilder("java", "...").start();
原因:
Could not find or load main class ...
好像系统变量或目录不同(它们不是)。另一方面,将其包装在 cmd.exe 中,如下所示:
new ProcessBuilder("cmd.exe", "/c", "java", "...").start();
工作,但创建另一个 cmd.exe 进程,它有一个副作用:子 JVM 现在是一个子子进程,并且process.destroy(); 不会杀死它(我在 Windows JRE 中的一个已知错误找到)。
由于所有这些应用程序都是我们的,而且我们知道它们的 PID,因此这个特定问题是在不同的级别上处理的。但这是一个示例 cmd.exe 如何使一切以不同的方式工作(或完全阻止 JVM 工作)。所以我想知道那里到底发生了什么。
在这里,框架本身也出现了。我们的测试平台也将使用它。我想提供一个 API,它允许使用 cmd.exe /c 通过参数包装命令。但是,该参数的具体含义是什么?用户如何决定是否需要 cmd.exe 包装?
还有一个我很感激的奖励:这在其他操作系统中是否相关?它是否有某种等价物,比如在 Linux 中?
【问题讨论】:
-
cmd /c 会用到一些环境变量,比如 CLASSPATH 和 PATH,而直接调用 java 会从父进程获取环境。这可以解释行为上的差异。找出你的进程环境和cmd环境的区别。
-
应用程序需要完全相同的变量,所以很奇怪。顺便说一句,java ... 命令包含所需的变量。缺少封闭的 cmd.exe 是否会导致它们被忽略?无论如何,这只是一个例子,但这就是问题所在:这个包装到底做了什么?环境、输出、返回值等。我还没找到答案。
-
根据我的经验,使用 cmd 获得的主要好处是变量替换和批处理文件支持(因此您可以调用批处理文件而不是可执行文件)。
-
你不需要它来调用一个批处理文件(即使这个批处理文件调用Java)。
-
@JPMoresmau:cmd.exe 实例将也从父进程中获取其环境变量,因此应该没有任何区别。我的猜测是,这与 Java 8 使用从 PATH 目录到实际可执行文件的符号链接有关。 (取决于 ProcessBuilder 在后台做了什么。)
标签: java windows cmd subprocess