2011-04-20 71 views
0

我需要在運行時設置環境變量,並在使用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值:::空

任何人都可以提出好的建議?

回答

3

當前java進程的環境不會被從它運行的子進程修改。 Runtime.exec創建一個子進程,它有自己的環境(初始化當前java進程的環境)。此子進程正在運行很短時間,然後終止。但是,這並沒有改變當前java(即父進程)進程的環境 - 這就是爲什麼父進程中的System.getenv仍然沒有env變量的值。

2

我不知道java但據我看到,您正在執行您的java程序(String[] command = {"sh", "-c", "cd" , ". ./.profile" };)的子shell中的所有命令。這意味着環境變量設置在此sh外殼中並導出到其子項。但父母(java程序)沒有看到這個變量。

0

檢查Runtime.exec的過載API。有一些可以讓你將環境變量作爲數組傳遞,例如exec(String[] cmdarray, String[] envp)

這就是如何將變量設置到子進程的環境中。但正如其他人所指出的,它不會幫助您訪問在父進程中的子進程中設置的環境變量。

您的真實需求尚不清楚,但這裏有一個將環境變量傳遞給子進程並在父進程中讀取變量(不設置變量)的示例。

下面是示例代碼:

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 
0

嘛,目前還不清楚爲什麼您的程序需要在.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(); 

這是一種更好的方法來寫環境變量到當前進程。

+0

我正在使用一個外部API,它需要FIC_HOME enc變量,並且在執行我的java代碼之前,不能在.profile中使用此變量。所以,我只需要從我的代碼中完成這項工作。我的.profile有一個echo語句,所以它應該在進程輸入流中。 – user709413 2011-04-21 13:18:15

0

基於以前的答案,您可以嘗試啓動shell而不是作爲子shell,而是通過命令「source」或「。」作爲父目錄的繼續。

0

@ user709413您的(hacky)文件爲基礎的方法將做的伎倆,但你需要使用除.profile之外的其他文件,導致它在用戶登錄過程中加載/讀取。因此,將值傳遞給例如$ {user.home} /your_app_name.store,並在另一個進程中讀取它。

但是,我建議使用除user.home之外的其他目錄,因爲它迫使您由同一用戶啓動所有進程,並且未來可能不會這樣。嘗試/ opt例如,並確保其他用戶將有讀取權限。