设置环境变量并在运行时获取值

时间:2011-04-20 12:15:52

标签: java unix environment

我需要在运行时设置一个环境变量,并使用JAVA在UNIX环境中获取该变量的值。 下面给出的是我的代码。但是,它无法获取环境变量,并且进程输出未显示在控制台中。不会抛出任何异常。

public static void main (String[] args) {
     String USR_HOME = System.getProperty("user.home");
     String profileName = USR_HOME+"/.profile";
     String installPath = System.getProperty("user.dir");
     String str = "";
      try {
      PrintWriter dynServ = new PrintWriter(new BufferedWriter(new FileWriter(profileName,true)));
      str = "FIC_HOME=" + installPath;
      dynServ.println(str);
      str = "export FIC_HOME";
      dynServ.println(str);
      dynServ.flush();
      dynServ.close();

        }catch (Exception e){

        System.out.println(e.getMessage());
      }

  ProcessBuilder pb = new ProcessBuilder("sh","-c",". ./.profile");
  Map<String, String> env = pb.environment();
  env.put("FIC_HOME", USR_HOME+"/Path");
  pb.directory(new File(USR_HOME));
    try {
        Process p = pb.start();
        BufferedReader Inreader = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line="";
           while ((line=Inreader.readLine())!=null)
             {
                System.out.println(line);
                //System.err.println(line);
              }
    } catch (Exception ex) {
        System.out.println("Exeception ::: "+ex.getMessage());
    }

System.out.println("FIC_HOME value :::"+System.getenv("FIC_HOME"));

输出是: .profile执行 FIC_HOME值::: null

有人可以提出建议吗?

6 个答案:

答案 0 :(得分:3)

当前的java进程'环境不会被从它运行的子进程修改。 您的Runtime.exec创建了一个子进程,它有自己的环境(从当前java进程的环境初始化)。此子进程运行一小段时间,然后终止。然而,这根本没有改变当前java(即父级)进程的环境 - 这就是为什么父进程上的System.getenv仍然没有env var的值。

答案 1 :(得分:2)

我不知道java但是据我所知,您正在执行java程序(String[] command = {"sh", "-c", "cd" , ". ./.profile" };)的子shell中的所有命令。这意味着环境变量在此sh shell中设置并导出到其子项。但是父(java程序)没有看到这个变量。

答案 2 :(得分:0)

检查Runtime.exec的重载API。有一些允许您将环境变量作为数组传递,例如exec(String[] cmdarray, String[] envp)

这就是你如何将变量设置到子进程的环境中。但正如其他人所说,它不会帮助您访问父进程中子进程中设置的环境变量。

您的实际需求尚不清楚,但这里是一个将环境变量传递给子进程并在父Java进程中读回变量(不设置变量)的示例。

以下是示例代码:

import java.io.*;

public class EnvTest {
  public static void main(String[] args) throws Exception {
    String[] cmd = {"sh","-c","env | grep FIC_HOME"};
    String[] envp = {"FIC_HOME=foo"};
    Process p = Runtime.getRuntime().exec(cmd, envp);
    BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String line = null;
    while ((line = reader.readLine()) != null) {
       System.err.println(line);
    }
  }
}

示例输出:

$ java EnvTest
FIC_HOME=foo

答案 3 :(得分:0)

嗯,目前尚不清楚为什么你的程序需要在.profile文件中定义一个环境变量。如果你澄清你真正想要实现的目标,也许我们可以提供更多帮助。您当前的方法听起来不是一个好主意,因为如果它已经包含有价值的信息,您将需要非常小心,不要错误地覆盖.profile文件。

现在,有一种简单的方法可以使用流程对象的错误输出流来检查是否出现任何错误。

您还可以阅读.profile文件,看看它的内容是否与您打算在其上写的内容相匹配。

你的第二块代码似乎只是运行你编写环境变量的.profile文件。我只能假设你的.profile文件只说:

FIC_HOME=/home/edalorzo/
export FIC_HOME

因此,当您在第二个过程中运行代码时,我不明白为什么应该生成任何特定输出。

写完文件后,您还可以检查您的命令是否实际正在正确读取.profile文件。

sh命令说明如下

  

-c选项导致命令   从字符串操作数中读取   而不是从标准输入。   请记住,仅此选项   接受一个字符串作为它   参数,因此多字符串   必须引用。

因此,你可能错误地使用了sh -c命令。

最后,正如其他人所说,当进程启动时,将填充Java进程的环境变量。如果将新变量写入操作系统,Java将无法实现。

您可能希望改为考虑流程构建器:

ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();

这是将环境变量写入当前进程的更好方法。

答案 4 :(得分:0)

根据之前的答案,您可以尝试将shell作为子shell启动,而不是通过命令“source”或“。”继续使用shell。

答案 5 :(得分:0)

@ user709413你的(hacky)基于文件的方法可以解决问题,但你需要使用.profile以外的其他文件,因为它在用户登录时加载/读取。所以将值传递给,例如:$ {user.home} /your_app_name.store,并在另一个过程中读取它。

但是,我建议使用除user.home之外的其他目录,因为它会强制您启动同一用户的所有进程,并且将来可能不是这种情况。尝试/ opt例如,并确保其他用户具有读取权限。