我在Java (1.6)中设置Linux环境时遇到了一个奇怪的问题;特别是"PATH“变量。
简而言之,我有一个运行本机进程的管道,它使用java.lang.ProcessBuilder
。用户可以选择通过名为environment
的HashMap
设置环境变量
ProcessBuilder pb = new ProcessBuilder(args);
Map<String, String> env = pb.environment();
if (environment != null)
env.putAll(environment);
Process process = pb.start();
如果我将env
变量转储到控制台,则会正确设置该变量,并为PATH变量指定正确的值。但是,运行该进程会导致抛出Exception
java.io.IOException: error=2, No such file or directory
在终端shell中使用相同的环境变量可以很好地运行相同的进程。为了测试这一点,我在终端中设置了环境之后运行了Eclipse。在这种情况下,ProcessBuilder
进程可以正确运行。
因此,必须发生的是,ProcessBuilder
使用的不是我为其设置的环境,而是当前的系统环境。
我在网上找不到这个问题的令人满意的答案。也许这是特定于操作系统的问题?或者我还漏掉了什么?
发布于 2012-04-05 21:37:37
我不认为这是一个bug,我认为这是你对环境变量的边界和角色的理解的问题。ProcessBuilder.environment()
包含的环境变量对于衍生的进程来说是“本地进程”的。它们不是系统范围的,也不是登录范围的,它们甚至不会影响ProcessBuilder运行的环境。
ProcessBuilder.environment()
映射包含进程本地变量,派生的进程只能在中看到这些变量。显然,看到ProcessBuilder.environment()
的派生进程的先决条件是成功派生进程,这是我认为您甚至还没有达到的点。
据我所知,(从Java中)修改当前运行的进程的路径是不可能的,我认为这是您期望发生的事情(或者能够做到的事情)。因此,我认为您必须将ProcessBuilder指向您尝试启动的可执行文件的完全限定路径(或者确保在启动将使用ProcessBuilder的JVM之前正确设置了该路径,这就是您在启动集成开发环境之前在终端中设置它的“工作”场景中所做的)。
发布于 2012-05-22 16:55:16
在Linux上:
String path = System.getenv("HOME");
ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","export PATH=" +
"PATH-TO-ADD" + ":" + path + " && exec");
在这种情况下,会根据需要更新PATH
变量,并在新的$PATH
中搜索可执行文件。这对我在Linux上是有效的。
发布于 2015-12-03 08:34:05
您需要了解环境变量是流程上下文的局部变量。一个新进程获得父进程环境的副本,但每个副本都是独立的。父对象中的更改不会影响现有的子项(仅影响新的子项),子项中的更改也不会影响父项或父项的新子项。
在本例中,Java进程创建子进程,并将修改后的PATH
变量放入子进程的上下文中。这不会影响Java进程。子进程不是shell,因此它忽略了PATH
变量。该进程直接使用操作系统服务创建。它们会查看Java进程的上下文,其中包含旧的PATH
变量,除非您在启动Java进程之前更改了shell中的环境。
要解决您的问题,您有两个选择:
PATH
变量,将其拆分成路径元素,然后手动搜索可执行文件。然后,您可以使用绝对路径调用ProcessBuilder
,并将新的PATH
放入子进程中,这样孙子进程就会具有正确的路径。传递
第二种情况是这样的:
使用正确的PATH
.
"sh", "-c", "cmd args"
或"cmd.exe", "/c", "cmd args"
)
PATH
并运行正确的命令。<>G227>
第二种情况的缺点是,您必须正确地转义和/或引用命令的参数(args
),否则空格和其他特殊字符将导致问题。
https://stackoverflow.com/questions/10035383
复制