2010-08-05 13 views
28

C'è un modo per impostare le variabili d'ambiente in Linux usando C?Imposta variabili d'ambiente in C

Ho provato setenv() e putenv(), ma non sembrano funzionare per me.

+0

Perché pensi che non abbiano funzionato? (Cioè, come hai provato questo? Getenv?) –

+0

Potresti postare un esempio di codice e una demo che mostra come non funzionano? – FrustratedWithFormsDesigner

risposta

44

Qui farò un'ipotesi, ma la normale ragione per cui queste funzioni sembrano non funzionare non è perché non funzionano, ma perché l'utente non capisce veramente come funzionano le variabili di ambiente. Per esempio, se ho questo programma:

int main(int argc, char **argv) 
{ 
    putenv("SomeVariable=SomeValue"); 
    return 0; 
} 

E poi ho eseguito dalla shell, esso non modifica l'ambiente della shell - non c'è modo per un processo figlio per farlo. Ecco perché i comandi della shell che modificano l'ambiente sono incorporati e perché è necessario lo source uno script che contenga le impostazioni variabili che si desidera aggiungere alla shell, anziché semplicemente eseguirlo.

+0

Il corollario di questo è ottenere il comportamento del "programma di esecuzione per impostare le variabili" nella shell che si è 1) scrivere uno script di shell per fare il lavoro e 2) non eseguirlo nel modo usuale, ma piuttosto "sorgente". (Nella maggior parte delle shell, '. Script' è lo stesso di' source script' e molto meno digitando.) – dmckee

+0

Questo ha molto senso, grazie :) Sì, era quello che stavo facendo. Sono nuovo di Linux, quindi scusami se questa è una domanda stupida, ma non c'è modo per un processo figlio di impostare l'ambiente di shell in C, e non di approvare uno script. Sono internato in questa azienda e mi è stato chiesto di scrivere una funzione per impostare il fuso orario di un dispositivo che esegue Linux, quindi stavo cercando di impostare l'ambiente TZ della shell. – iman453

+0

@iman: prova 'man -k tz' per alcune opzioni. Sulla mia macchina Mac OS X viene visualizzato 'tzset (3)' ... – dmckee

5

La variabile di ambiente impostata da setenv()/putenv() verrà impostata per il processo che esegue queste funzioni e sarà ereditata dai processi avviati da esso. Tuttavia, non sarà trasmesso nella shell che ha eseguito il programma.

Why isn't my wrapper around setenv() working?

1

Il blocco di ambiente è un processo locale, e copiato in processi figli. Quindi, se si modificano le variabili, il nuovo valore influisce solo sul processo e sui processi figli generati dopo la modifica. Sicuramente non cambierà la shell da cui sei partito.

-2

L'ho ricevuto dal mio "Advanced Programming in the UNIX Environment" book.

L'ambiente elenca l'array di puntatori alle stringhe nome = valore corrente e le stringhe di ambiente in genere sono memorizzate nella parte superiore dello spazio di memoria di un processo, sopra lo stack.

L'eliminazione di una stringa è semplice; troviamo semplicemente il puntatore nell'elenco degli ambienti e spostiamo tutti i puntatori successivi in ​​basso di uno. Ma aggiungere una stringa o modificare una stringa esistente è più difficile. Lo spazio nella parte superiore della pila non può essere espanso, perché è spesso nella parte superiore dello spazio degli indirizzi del processo e quindi non può espandersi verso l'alto; non può essere espanso verso il basso, perché non è possibile spostare tutti i frame dello stack sottostanti.

  1. Se stiamo modificando un nome esistente:

    a. Se la dimensione del nuovo valore è inferiore o uguale alla dimensione del valore esistente, possiamo semplicemente copiare la nuova stringa sulla vecchia stringa.

    b. Se la dimensione del nuovo valore è maggiore di quella vecchia, tuttavia, dobbiamo malloc per ottenere spazio per la nuova stringa, copiare la nuova stringa in quest'area e quindi sostituire il vecchio puntatore nell'elenco di ambienti per nome con il puntatore a questa area allocata.

  2. Se aggiungiamo un nuovo nome, è più complicato. Per prima cosa, dobbiamo chiamare malloc per allocare spazio per la stringa name = value e copiare la stringa in quest'area.

    a. Quindi, se è la prima volta che aggiungiamo un nuovo nome, dobbiamo chiamare malloc per ottenere spazio per un nuovo elenco di puntatori.Copiamo la vecchia lista di ambienti in questa nuova area e memorizziamo un puntatore alla stringa name = value alla fine di questo elenco di puntatori. Memorizziamo anche un puntatore nullo alla fine di questo elenco, ovviamente. Infine, impostiamo environ per puntare a questa nuova lista di puntatori. se l'elenco di ambiente originale era contenuto sopra la cima dello stack, come è comune, abbiamo spostato questo elenco di puntatori all'heap. Ma la maggior parte dei puntatori in questa lista puntano ancora su stringhe name = value sopra la cima della pila.

    b. Se non è la prima volta che aggiungiamo nuove stringhe all'elenco degli ambienti, sappiamo che abbiamo già allocato spazio per la lista sullo heap, quindi chiamiamo solo realloc per allocare spazio per un altro puntatore. Il puntatore alla nuova stringa name = value viene archiviato alla fine dell'elenco (sopra il precedente puntatore nullo), seguito da un puntatore nullo.

Tutto il meglio.

+0

Non sono sicuro di aver capito la domanda dell'OP ... – dmckee

+0

Sei corretto :-). La mia comprensione è che sta affrontando alcuni nel suo eseguibile dopo aver impostato le variabili di env. – Hemant

9

Qualsiasi programma unix viene eseguito in un processo separato dal processo che lo avvia; questo è un processo "figlio".

Quando si avvia un programma, che sia sulla riga di comando o in qualsiasi altro modo, il sistema crea un nuovo processo che è (più o meno) una copia del processo genitore. Quella copia include le variabili di ambiente nel processo genitore, e questo è il meccanismo mediante il quale il processo figlio "eredita" le variabili d'ambiente del suo genitore. (Questo è tutto in gran parte quello che altri hanno detto risposte qui)

Cioè, un processo solo mai definisce i suoi propri variabili d'ambiente.

Altri hanno menzionato l'uso di uno script di shell come metodo per impostare le variabili di ambiente nel processo corrente, ma se è necessario impostare variabili nel processo corrente (shell) a livello di codice, allora c'è un modo leggermente indiretto che è possibile .

Considerate questo:

% cat envs.c 
#include <stdio.h> 
int main(int argc, char**argv) 
{ 
    int i; 
    for (i=1; i<argc; i++) { 
     printf("ENV%d=%s\n", i, argv[i]); 
    } 
} 
% echo $ENV1 

% ./envs one two 
ENV1=one 
ENV2=two 
% eval `./envs one two` 
% echo $ENV1 
one 
% 

Il built-in eval valuta il suo argomento, come se tale argomento è stato digitato al prompt della shell. Questo è un esempio di sh-style; la variante in stile csh è lasciata come esercizio!

+0

Ho notato che questo è stato down-votato. Qualche indicazione sul perché? Qualcuno ha individuato un errore? –

+0

Non sono sicuro del motivo per cui qualcuno lo sottovaluterebbe. Strano. Sembra una buona soluzione per me! – wasatchwizard

+0

Suppongo che sia perché la risposta imposta la variabile d'ambiente usando il comando bash integrato 'eval', che sono le probabilità che il programmatore non sia in grado di usare bash affatto. Se al programmatore è permesso usare uno script di shell (che non è sempre il caso, da qui la domanda), ci sono altri modi più ovvi e migliori per impostare la variabile di ambiente oltre all'eval di bash specifico. (p.s. non ho fatto downvote) –