为ProcessBuilder设置环境

And*_*eid 10 java environment-variables processbuilder

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

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

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

env变量被设置正确,如果我把它转储到控制台,与PATH变量正确的值.但是,运行该进程会导致抛出Exception:

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

在终端shell中使用相同的环境变量运行相同的进程.为了测试这个,我在终端后设置环境后运行Eclipse.在这种情况下,该ProcessBuilder过程正确运行.

所以必须发生的是,ProcessBuilder我没有使用我为它设置的环境,而是使用当前的系统环境.

我在网上找不到任何满意的答案.也许这是特定于操作系统的问题?还是别的我错过了什么?

Mik*_*ark 13

我不认为这是一个错误,我认为你理解环境变量的边界和角色是一个问题. ProcessBuilder.environment()包含将对生成的进程"进程本地"的环境变量.它们不是系统范围的,也不是登录范围的,它们甚至不会影响运行ProcessBuilder的环境.

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

据我所知,(从Java)修改当前正在运行的进程'PATH是不可能的,这是我认为你期望发生的(或者能够做到的).所以我认为你必须指出ProcessBuilder到您尝试启动的可执行文件的完全限定路径(或者在您启动将使用ProcessBuilder的JVM之前确定PATH已正确设置,这是您在'工作'方案中所做的在启动IDE之前将其设置在终端中.


小智 7

在Linux上:

String path = System.getenv("HOME");

ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","export PATH=" +
    "PATH-TO-ADD" + ":" + path + " && exec");
Run Code Online (Sandbox Code Playgroud)

在这种情况下,PATH变量根据需要进行更新,并以新的方式搜索可执行文件$PATH.这在Linux上适用于我.


Aar*_*lla 6

您需要了解环境变量是过程上下文的本地变量.新进程获取父级环境的副本,但每个副本都是独立的.在父母的更改不会影响现有的儿童(仅适用于新的),并在孩子的变化不影响父母或新的孩子家长.

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

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

  1. 检查PATHJava中的变量,将其拆分为路径元素并手动搜索可执行文件.然后,您可以调用ProcessBuilder使用绝对路径,并把新PATH进的孩子,所以孙子都会有正确的路径.

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

第二种情况是这样的:

  1. 您创建一个正确的环境PATH.
  2. 你启动一个shell进程.
  3. 您将命令作为参数运行到shell("sh", "-c", "cmd args""cmd.exe", "/c", "cmd args")
  4. shell会注意到它必须运行命令
  5. 它将调查它的环境(您在步骤#1中配置),找到已修改的环境PATH并运行正确的命令.

第二种情况的缺点是你必须正确地转义和/或引用command(args)的参数,或者空格和其他特殊字符会引起问题.