2012-04-03 54 views
8

這裏我寫了一個C程序,它使用system調用執行hi.sh文件。使用C代碼獲取環境變量

在這裏,我用. ./hi.sh所以我想在同一個外殼 執行該腳本,然後嘗試使用GETENV函數獲取環境變量,但我在這裏跟我想象中得到不同的輸出。

hi.sh文件包含

export TEST=10 
return 

意思,當我使用系統調用運行此hi.sh文件,其export TEST設置在同一殼的價值爲10。 在此之後,我試圖得到這個變量值,但它的值爲NULL

如果我從控制檯像. ./hi.sh手動運行此腳本,那麼它工作正常,我得到TEST使用getenv("TEST")函數的10值。

代碼:

#include <stdio.h> 
int main() 
{ 
    system(". ./hi.sh"); 
    char *errcode; 
    char *env = "TEST"; 
    int errCode;  
    errcode = getenv(env); 
    printf("Value is = %s\n",errcode); 
    if (errcode != NULL) { 
     errCode =atoi(errcode); 
     printf("Value is = %d\n",errCode); 
    } 
} 

輸出:

Value is = (null) 

我如何導出測試變量在程序的殼呢?如果system()在不同shell中執行命令,那麼如何使用C程序代碼來獲取通過調用system()調用而調用的shell導出的環境變量?

回答

7

像往常一樣,手冊頁確實解釋了這一點,但您需要仔細閱讀。

DESCRIPTION 
     system() executes a command specified in command by calling /bin/sh -c 
     command, and returns after the command has been completed. During exe‐ 
     cution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT 
     will be ignored. 

換句話說,系統()第一次啓動/ bin/sh的,然後有/ bin/sh的開始要執行任何命令。 因此,這裏發生的是,TEST變量被導出到/ bin/sh shell中,系統()調用隱式地啓動,但不是調用system()的程序。

+0

那麼,我如何才能實現這一目標? – user1089679 2012-04-03 09:30:37

+0

如何將TEST變量導出到程序Shell? – user1089679 2012-04-03 09:33:24

+2

@ user1089679運行C程序之前,請編寫腳本(設置環境)。這就是環境變量設計使用的方式。 – 2012-04-03 09:51:37

0

您可以使用setenv()(其中system()然後默默地傳遞到子進程,或明確使用fork()execve()運行shell腳本通過變量設置環境變量在自己的過程。

+0

感謝您的回覆。但我必須使用系統調用調用shell腳本,並且必須從腳本設置環境變量。在此之後,我想從shell中獲取環境變量 – user1089679 2012-04-03 10:03:56

+2

這是不可能的。變量只能傳遞給新創建的進程,而不能傳回給父進程。您的腳本應該生成一些輸出,您可以使用'popen()'而不是'system()'來檢索輸出。 – 2012-04-03 10:16:39

9

孩子使用system()getenv()是註定要失敗的,因此進程不能直接設置父進程的環境。這種方法。

如果要導入由腳本hi.sh設置選定的變量,那麼你有兩個選擇。要麼你可以閱讀編寫腳本hi.sh,並找出它將它們設置爲的內容(相當困難),或者您可以運行該腳本並讓您運行的代碼向感興趣的環境變量返回報告。

假設hi.sh集合$ENV1$ENV2。您可以使用popen()將值返回給程序,並使用setenv()來設置程序的環境。概述:

FILE *fp = popen(". ./hi.sh; echo ENV1=$ENV1; echo ENV2=$ENV2", "r"); 

while (fgets(buffer, sizeof(buffer), fp) != 0) 
{ 
    ...split the buffer into env_name, env_value... 
    setenv(env_name, env_value); 
} 

pclose(fp); 

請注意,我將變量名稱包含在回顯信息中;這簡化了生活。如果你的變量列表變得笨重,也許你運行". ./hi.sh; env"來獲取整個環境,然後讀取每一行並從你的內建列表中找出它是否需要使用的變量設置。或者你可以簡單地設置你的整個環境,如果這讓你滿意。您應該檢查setenv()函數是否成功(它在成功時返回零)。您還應該檢查popen()是否成功(fp != 0)。在這種情況下,您可能可以使用strtok()查找=,將變量名與值分開;它在=踐踏一空字節,給你一個空值終止的名稱和空終止值:

char *env_name = strtok(buffer, "="); 
    char *env_value = buffer + strlen(env_name) + 1; 
    if (setenv(env_name, env_value) != 0) 
     ...report trouble... 
1

另一種可能的解決方案是通過另一個shell有你的程序exec本身。該shell替換正在運行的程序,然後讀取環境變量,然後用程序的新副本替換shell。你需要告訴新的副本,它已經完成了一個exec,或者它只會循環地做一遍又一遍。您可以查找環境變量,或者傳遞一個命令行標誌。

一個未經考驗的例子:

execl("/bin/sh", "-c", ". ./hi.sh; exec ./a.out --envset", NULL); 

您需要與任何真正的程序名稱是替代的a.out。您可能想要從argv [0]中提取它,並傳遞argv數組的其餘部分。但你必須將參數重新格式化爲shell參數,因此需要根據需要引用它們等。