Получить переменные окружения с помощью кода C - PullRequest
8 голосов
/ 03 апреля 2012

Здесь я написал программу на C, которая выполняет hi.sh файл, используя system call.

Здесь я использовал . ./hi.sh, поэтому я хочу выполнить этот скрипт в той же оболочке и затем попытайтесь получить переменную окружения с помощью функции getenv, но здесь я получаю вывод, отличный от того, что я ожидал.

Файл hi.sh содержит

export TEST=10
return

Означает, что когда я запускаю этот файл hi.sh с помощью системного вызова, его export TEST устанавливает значение 10 в той же оболочке. После этого я пытаюсь получить значение этой переменной, но ее значение NULL.

И если я запускаю этот скрипт вручную из консоли, как . ./hi.sh, то он работает нормально, и я получаю значение 10 TEST, используя функцию getenv("TEST").

код:

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

Как я могу экспортировать переменную TEST в программной оболочке? Если system() выполняет команды в другой оболочке, то как я могу использовать программный код на C, чтобы получить переменную среды, которая экспортируется оболочкой, вызванной с помощью вызова system()?

Ответы [ 4 ]

9 голосов
/ 03 апреля 2012

Дочерний процесс не может напрямую устанавливать среду родительского процесса.Подход с использованием 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...
7 голосов
/ 03 апреля 2012

Как обычно, справочная страница объясняет это, но вы должны прочитать ее очень внимательно.

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.

Другими словами, system () сначала запускает / bin / sh, а затем / bin / sh запускает любую команду, которую вы хотите выполнить. Таким образом, здесь происходит то, что переменная TEST экспортируется в оболочку / bin / sh, которая неявно запускается вызовом system (), но не в программу, которая вызвала system ().

1 голос
/ 20 октября 2015

Другое возможное решение - использовать вашу программу exec через другую оболочку. Эта оболочка заменяет работающую программу, затем считывает переменные среды и затем заменяет оболочку новой копией программы. Вы должны сообщить новой копии, что она уже выполнила exec или она будет повторять цикл снова и снова. Вы можете найти переменную среды или передать флаг командной строки.

Непроверенный пример:

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

Вам необходимо заменить a.out на любое имя программы. Возможно, вы захотите извлечь его из argv [0], а также передать остаток массива argv. Но вы должны переформатировать аргументы, чтобы они работали как аргументы оболочки, поэтому их нужно заключать в кавычки по мере необходимости и т. Д.

0 голосов
/ 03 апреля 2012

Вы можете либо установить переменную среды в своем собственном процессе, используя setenv() (который system() затем молча перейдет к дочерним процессам, либо явно передать переменные, используя fork() и execve() для запуска сценария оболочки .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...