2012-04-03 12 views
8

Tutaj napisałem program w języku C, który wykonuje plik hi.sh przy użyciu połączenia system.Pobierz zmienne środowiskowe za pomocą kodu C

Tutaj użyłem . ./hi.sh więc chcę, aby wykonać ten skrypt w tej samej powłoce a następnie postarać się zmienną środowiskową za pomocą funkcji getenv, ale tutaj jestem coraz innego wyjścia z tego się spodziewałem.

Plik hi.sh zawiera

export TEST=10 
return 

Środki gdy uruchamiam ten plik hi.sh użyciu wywołania systemowego, jego export TEST ustawia wartość do 10 w tej samej powłoki. Po tym, próbuję uzyskać tę wartość zmiennej, ale jego podana wartość NULL.

Jeśli uruchomię ten skrypt ręcznie z poziomu konsoli, np. . ./hi.sh, to działa poprawnie i otrzymuję 10 wartości TEST przy użyciu funkcji getenv("TEST").

Kod:

#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); 
    } 
} 

wyjściowa:

Value is = (null) 

Jak mogę wyeksportować zmienną TEST skorupek programu? Jeśli system() wykonuje komendy w innej powłoce, to w jaki sposób mogę użyć kodu programu C, aby uzyskać zmienną środowiskową wyeksportowaną przez powłokę wywołaną przez wywołanie system()?

Odpowiedz

7

Jak zwykle, strona podręcznika wyjaśnia to, ale trzeba ją uważnie przeczytać.

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. 

Innymi słowy system() pierwsza uruchamia/bin/sh, a następnie ma/bin/sh zacząć cokolwiek polecenie, które chcesz wykonać. Co się dzieje tutaj, to że zmienna TEST jest eksportowana do powłoki/bin/sh wywołanie system() niejawnie rozpoczęte, ale nie do programu, który wywołał system().

+0

Jak mogę osiągnąć ten cel? – user1089679

+0

Jak mogę wyeksportować zmienną TEST do programu Shell? – user1089679

+2

@ user1089679 Źródło swojego skryptu (skonfiguruj środowisko) przed uruchomieniem programu C. W ten sposób zaprojektowano zmienne środowiskowe, które mają być używane. –

0

Można też ustawić zmienną środowiskową w swoim własnym procesie korzystania setenv() (który system() następnie dyskretnie przekazuje do procesów potomnych, lub jawnie przekazać zmienne za pomocą fork() i execve() aby uruchomić skrypt.

+0

dzięki za odpowiedź. Ale muszę wywołać skrypt powłoki przy użyciu wywołania systemowego i jego konieczne ustawienie zmiennych środowiskowych ze skryptu. Po tym chcę uzyskać zmienne środowiskowe z powłoki – user1089679

+2

To nie jest możliwe. Zmienne można przekazywać tylko do nowo utworzonych procesów, a nie do procesu nadrzędnego. Twój skrypt powinien wygenerować trochę danych wyjściowych, które możesz odzyskać za pomocą 'popen()' zamiast 'system()'. –

9

Dziecko proces nie może bezpośrednio ustawić środowisko procesu nadrzędnego. podejście za pomocą system() i getenv() jest skazane na niepowodzenie, dlatego.

Jeśli próbujesz importować wybrane zmienne ustawione przez skrypt hi.sh, to masz kilka opcji do wyboru. Albo można przeczytać skrypt hi.sh i ustal, do czego byłby ustawiony (raczej twardy), lub możesz uruchomić skrypt i uruchomić wygenerowany przez niego kod z powrotem na interesujące zmienne środowiskowe.

Załóżmy, że hi.sh ustawia $ENV1 i $ENV2. Możesz użyć wartości popen(), aby przywrócić wartości do swojego programu, oraz setenv(), aby ustawić środowisko swojego programu.Zarys:

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); 

Należy pamiętać, że zawarłem nazwę zmiennej w wyświetlanej informacji; to upraszcza życie. Jeśli twoja lista zmiennych staje się nieporęczna, możesz uruchomić ". ./hi.sh; env", aby uzyskać całe środowisko, a następnie przeczytać każdą linię i opracować z wbudowanej listy, czy jest to zmienne ustawienie, którego chcesz użyć, czy nie. Możesz też ponownie ustawić całe środowisko, jeśli ci się to podoba. Powinieneś sprawdzić, czy funkcja setenv() powiodła się (zwraca zero, gdy się powiedzie). Powinieneś również sprawdzić, czy popen() zakończyło się powodzeniem (fp != 0). W tym kontekście prawdopodobnie można użyć strtok(), aby wyszukać = oddzielając nazwę zmiennej od wartości; to depcze zerowy bajt nad =, co daje NUL nazwę i NUL wartość:

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

Innym możliwym rozwiązaniem jest mieć swój program exec się za pośrednictwem innej powłoki. Ta powłoka zastępuje uruchomiony program, następnie odczytuje zmienne środowiskowe, a następnie zastępuje powłokę nową kopią programu. Musisz poinformować nową kopię, że wykonała już komendę exec lub po prostu uruchomi ją w kółko. Możesz wyszukać zmienną środowiskową lub przekazać flagę linii poleceń.

nieprzetestowanym przykład:

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

Trzeba by wymienić a.out z cokolwiek nazwa prawdziwy program. Prawdopodobnie chcesz wyodrębnić go z argv [0], a także przekazać resztę tablicy argv. Ale musisz sformatować argumenty, aby działały jako argumenty powłoki, więc muszą być cytowane w razie potrzeby, itp.