2012-04-03 49 views
8

Aquí escribí un programa C que ejecuta el archivo hi.sh usando la llamada system.Obtener variables de entorno usando el código C

Aquí utilicé . ./hi.sh así que quiero ejecutar este script en el mismo shell y luego tratar de obtener la variable de entorno usando la función getenv, pero aquí obtengo resultados diferentes de los que esperaba.

El archivo hi.sh contiene

export TEST=10 
return 

significa que cuando corro este archivo hi.sh usando la llamada sistema, su export TEST establece el valor en 10 en la misma carcasa. Después de esto, estoy tratando de obtener este valor variable, pero se le da valor NULL.

Y si ejecuto este script manualmente desde la consola como . ./hi.sh entonces funciona bien y obtengo el valor 10 de TEST usando la función getenv("TEST").

Código:

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

de salida:

Value is = (null) 

¿Cómo puedo exportar variable de prueba en el programa de shell? Si system() ejecuta comandos en un shell diferente, entonces, ¿cómo puedo usar el código del programa C para obtener una variable de entorno que es exportada por el shell invocado a través de una llamada system()?

Respuesta

7

Como es habitual, la página de manual explica esto, pero debe leerlo detenidamente.

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. 

En otras palabras, el sistema() primero inicia/bin/sh, y luego tiene/bin/sh empezar el comando que desea ejecutar. Entonces, lo que ocurre aquí es que la variable TEST se exporta a la shell/bin/sh la llamada al sistema() se inició implícitamente, pero no al programa que llamó a system().

+0

Entonces, ¿cómo puedo lograr este objetivo? – user1089679

+0

¿Cómo puedo exportar la variable TEST para programar Shell? – user1089679

+2

@ user1089679 Fuente su script (configurar el entorno) antes de ejecutar su programa C. Así es como se diseñaron las variables de entorno para su uso. –

0

Puede configurar la variable de entorno en su propio proceso utilizando setenv() (que system() continuación, pasa en silencio a los procesos secundarios, o explícitamente pasar las variables mediante el uso de fork() y execve() para ejecutar el script de shell.

+0

gracias por su respuesta. Pero tengo que llamar al script de shell usando la llamada al sistema y es necesario para establecer las variables de entorno desde el script. Después de esto quiero obtener variables de entorno del shell – user1089679

+2

Eso no es posible. Las variables solo se pueden pasar a los procesos recién creados, no al proceso principal. Su secuencia de comandos debe generar algún resultado, que puede recuperar utilizando 'popen()' en lugar de 'system()'. –

9

El niño proceso no puede establecer directamente el entorno del proceso padre. el método que utiliza system() y getenv() está condenado al fracaso, por lo tanto.

Si está intentando importar variables seleccionadas establecidos por el guión hi.sh, entonces usted tiene un par de opciones. O bien puedo leer la secuencia de comandos hi.sh y averigüe qué les asignaría (más bien difícil), o puede ejecutar la secuencia de comandos y hacer que el código que ejecuta informe nuevamente sobre las variables de entorno de interés.

Supongamos que hi.sh establece $ENV1 y $ENV2. Puede usar popen() para obtener los valores de vuelta a su programa y setenv() para configurar el entorno de su programa.En resumen:

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

Tenga en cuenta que incluí el nombre de la variable en la información repetida; esto simplifica la vida. Si su lista de variables se vuelve difícil de manejar, tal vez ejecute ". ./hi.sh; env" para obtener todo el entorno, y luego lea cada línea y resuelva desde su lista incorporada si es una configuración de variable que desea usar o no. O simplemente puede configurar todo el entorno nuevamente, si eso le agrada. Debería verificar que la función setenv() tuvo éxito (devuelve cero cuando tiene éxito). También debe verificar que el popen() fue exitoso (fp != 0). En este contexto, probablemente pueda usar strtok() para buscar el = separando el nombre de la variable del valor; pisotea un byte nulo sobre el =, dándole un terminada en nulo nombre y un valor nulo terminado:

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

Otra posible solución es hacer que su programa exec sí a través de otra línea de comandos. Ese shell reemplaza el programa en ejecución, luego lee las variables de entorno y luego reemplaza el shell con una nueva copia del programa. Necesitas decirle a la nueva copia que ya ha hecho un ejecutivo o que simplemente lo repetirá una y otra vez. Puede buscar la variable de entorno o pasar un indicador de línea de comando.

Un ejemplo no probado:

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

Usted tendría que sustituir a.out con lo que el nombre del programa real. Probablemente quieras extraerlo de argv [0] y pasar el resto de la matriz argv. Pero tiene que volver a formatear los argumentos para que funcionen como argumentos de shell, por lo que deben citarse según sea necesario, etc.

Cuestiones relacionadas