为 ProcessBuilder 设置环境

我有一个奇怪的问题从Java设置Linux环境(1.6);特别是“PATH”变量。

简而言之,我有一个用于运行本机进程的管道,它使用.用户可以选择通过命名的设置环境变量:java.lang.ProcessBuilderHashMapenvironment

ProcessBuilder pb = new ProcessBuilder(args);
Map<String, String> env = pb.environment();
if (environment != null)
   env.putAll(environment);
Process process = pb.start();

如果我将变量转储到控制台,则该变量将正确设置,并为 PATH 变量提供正确的值。但是,运行该进程会导致抛出:envException

java.io.IOException: error=2, No such file or directory

在终端 shell 中使用相同的环境变量时,相同的过程运行良好。为了测试这一点,我在终端中设置环境后运行了Eclipse。在这种情况下,进程将正常运行。ProcessBuilder

因此,必须发生的是,使用的不是我为其设置的环境,而是当前的系统环境。ProcessBuilder

我无法在网上找到这个问题的任何令人满意的答案。也许这是一个特定于操作系统的问题?还是我错过了别的东西?


答案 1

我不认为这是一个错误,我认为这是你对环境变量的边界和作用的理解有问题。 包含环境变量,这些变量将对生成的进程进行“进程局部”。它们不是系统范围的,也不是登录范围的,它们甚至不会影响运行 ProcessBuilder 的环境。ProcessBuilder.environment()

该映射包含进程局部变量,只有生成的进程才能看到这些变量。显然,看到生成处理的先决条件是该过程的成功生成,这是我认为您甚至没有达到的一点。ProcessBuilder.environment()ProcessBuilder.environment()

据我所知,(从Java)修改当前正在运行的进程PATH是不可能的,我认为这是你期望发生(或能够做到)的。因此,我认为您必须将 ProcessBuilder 指向您尝试启动的可执行文件的完全限定路径(或者确定在启动将使用 ProcessBuilder 的 JVM 之前正确设置了 PATH,这是您在启动 IDE 之前在终端中设置它的“工作”场景中所做的)。


答案 2

您需要了解环境变量是流程上下文的本地变量。新进程获取父级环境的副本,但每个副本都是独立的。父项中的更改不会影响现有子项(仅影响新子项),并且子项中的更改不会影响父项或父项的新子项

在您的例子中,Java 进程创建子进程,并将修改后的变量放入子进程的上下文中。这不会影响 Java 进程。子进程不是 shell,因此它会忽略该变量。该过程是直接使用 OS 服务创建的。这些查看包含旧变量的 Java 进程的上下文,除非您在启动 Java 进程之前更改 shell 中的环境。PATHPATHPATH

要解决您的问题,您有两种选择:

  1. 检查 Java 中的变量,将其拆分为路径元素,然后手动搜索可执行文件。然后,您可以使用绝对路径调用并将新路径放入子级,以便孙子孙女将拥有正确的路径。PATHProcessBuilderPATH

  2. 调用 shell 以启动子进程。shell 将使用它的路径(你可以通过环境传递)。

第二种情况是这样的:

  1. 使用正确的 .PATH
  2. 启动一个外壳程序进程。
  3. 将命令作为参数运行传递给 shell ( 或"sh", "-c", "cmd args""cmd.exe", "/c", "cmd args")
  4. shell 会注意到它必须运行一个命令
  5. 它将查看其环境(您在步骤#1中配置),找到修改后的环境并运行正确的命令。PATH

第二种情况的缺点是,您必须正确转义和/或引用命令()的参数,否则空格和其他特殊字符会导致问题。args


推荐