2010-08-05 14 views
28

Gibt es eine Möglichkeit, Umgebungsvariablen in Linux mit C zu setzen?Umgebungsvariablen in C setzen

Ich versuchte setenv() und putenv(), aber sie scheinen nicht für mich arbeiten.

+0

Warum glaubst du, dass sie nicht funktionierten? (Das heißt, wie haben Sie das getestet? Getenv?) –

+0

Könnten Sie ein Codebeispiel und eine Demo veröffentlichen, die zeigen, wie sie nicht funktionieren? – FrustratedWithFormsDesigner

Antwort

44

Ich werde hier eine wilde Vermutung machen, aber der normale Grund, dass diese Funktionen scheinbar nicht funktionieren, ist nicht, weil sie nicht funktionieren, sondern weil der Benutzer nicht wirklich versteht, wie Umgebungsvariablen funktionieren. wenn ich dieses Programm habe zum Beispiel:

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

Und dann habe ich es von der Shell ausgeführt, wird es nicht die Umgebung des Shell zu ändern - es gibt keine Möglichkeit für einen Kind-Prozess, das zu tun. Aus diesem Grund sind die Shell-Befehle, die die Umgebung modifizieren, eingebaut und Sie müssen source ein Skript, das variable Einstellungen enthält, die Sie zu Ihrer Shell hinzufügen möchten, anstatt es einfach auszuführen.

+0

Die logische Folge davon ist, das "run program to set Variablen" Verhalten in der Shell zu bekommen 1) schreibe ein Shell-Skript, um den Job zu machen und 2) führe es nicht wie üblich aus, sondern "quelle" es. (BTW in den meisten Shells '. Script' ist das selbe wie' source script' und viel weniger tippen.) – dmckee

+0

Das macht sehr viel Sinn, danke :) Ja, das war was ich gemacht habe. Ich bin neu in Linux, also verzeiht mir, wenn das eine dumme Frage ist, aber gibt es überhaupt keine Möglichkeit für einen Kindprozess, die Shellumgebung in C zu setzen und kein Skript zu erstellen. Ich interniere bei dieser Firma, und ich wurde gebeten, eine Funktion zu schreiben, um die Zeitzone eines Geräts zu setzen, das Linux ausführt, also versuchte ich, die TZ-Umgebung der Schale einzustellen. – iman453

+0

@iman: versuchen Sie 'man -k tz 'für einige Optionen. Auf meiner Mac OS X Maschine, was sich zeigt, ist 'tzset (3)' ... – dmckee

5

Die von setenv()/putenv() festgelegte Umgebungsvariable wird für den Prozess festgelegt, der diese Funktionen ausführt, und wird von den von ihm gestarteten Prozessen geerbt. Es wird jedoch nicht gesendet in die Shell, die Ihr Programm ausgeführt.

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

1

Der Umgebungsblock ist prozess lokalen und auf untergeordnete Prozesse kopiert. Wenn Sie also Variablen ändern, wirkt sich der neue Wert nur auf Ihren nach der Änderung erzeugten Prozess und die untergeordneten Prozesse aus. Sicherlich wird es die Shell, von der Sie gestartet haben, nicht ändern.

-2

Ich habe es von meinem "Advanced Programming in the UNIX Environment" Buch.

Die Umgebung listet das Array der Zeiger auf die tatsächlichen Zeichenfolgen name = value auf, und die Umgebungszeichenfolgen werden in der Regel oben im Speicher eines Prozesses über dem Stapel gespeichert.

Löschen einer Zeichenfolge ist einfach; Wir finden den Zeiger in der Umgebungsliste und verschieben alle nachfolgenden Zeiger um eins nach unten. Das Hinzufügen einer Zeichenfolge oder das Ändern einer vorhandenen Zeichenfolge ist jedoch schwieriger. Der Speicherplatz am oberen Rand des Stapels kann nicht erweitert werden, da er oft oben im Adressraum des Prozesses liegt und daher nicht nach oben expandieren kann. Es kann nicht nach unten erweitert werden, da alle darunter liegenden Stapelrahmen nicht verschoben werden können.

  1. Wenn wir einen bestehenden Namen sind ändern:

    ein. Wenn die Größe des neuen Werts kleiner oder gleich der Größe des vorhandenen Werts ist, können Sie einfach die neue Zeichenfolge über die alte Zeichenfolge kopieren.

    b. Wenn die Größe des neuen Werts jedoch größer als der alte Wert ist, müssen wir malloc Platz für die neue Zeichenfolge erhalten, die neue Zeichenfolge in diesen Bereich kopieren und dann den alten Zeiger in der Umgebungsliste durch name ersetzen Zeiger auf diesen zugewiesenen Bereich.

  2. Wenn wir einen neuen Namen hinzufügen, ist es komplizierter. Zuerst müssen wir malloc aufrufen, um Platz für die name = value-Zeichenfolge zuzuweisen und die Zeichenfolge in diesen Bereich zu kopieren.

    a. Dann, wenn es das erste Mal ist, dass wir einen neuen Namen hinzugefügt haben, müssen wir malloc aufrufen, um Platz für eine neue Liste von Zeigern zu erhalten.Wir kopieren die alte Umgebungsliste in diesen neuen Bereich und speichern einen Zeiger auf die Zeichenfolge name = value am Ende dieser Zeigerliste. Wir speichern natürlich auch einen Nullzeiger am Ende dieser Liste. Schließlich setzen wir environ, um auf diese neue Zeigerliste zu zeigen. Wenn die ursprüngliche Umgebungsliste wie üblich über dem Anfang des Stapels enthalten war, haben wir diese Zeigerliste auf den Heap verschoben. Die meisten Zeiger in dieser Liste verweisen jedoch immer noch auf Zeichenfolgen name = value oberhalb des Stacks.

    b. Wenn dies nicht das erste Mal ist, dass wir der Umgebungsliste neue Zeichenfolgen hinzugefügt haben, wissen wir, dass wir bereits Platz für die Liste auf dem Heap reserviert haben. Daher rufen wir einfach realloc auf, um Platz für einen weiteren Zeiger zuzuweisen. Der Zeiger auf die neue name = value-Zeichenfolge wird am Ende der Liste (über dem vorherigen Nullzeiger) gespeichert, gefolgt von einem Nullzeiger.

Alles Gute.

+0

Ich bin mir nicht sicher, ob Sie die Frage des OP verstanden haben ... – dmckee

+0

Sie haben Recht :-). Mein Verständnis war, dass er einige in seiner ausführbaren Datei vorstellt, nachdem env-Variablen gesetzt wurden. – Hemant

9

Jedes Unix-Programm wird in einem separaten Prozess von dem Prozess ausgeführt, der es startet; Dies ist ein "Kind" -Prozess.

Wenn ein Programm gestartet wird - sei es in der Befehlszeile oder auf andere Weise - erstellt das System einen neuen Prozess, der (mehr oder weniger) eine Kopie des übergeordneten Prozesses ist. Diese Kopie enthält die Umgebungsvariablen im übergeordneten Prozess. Dies ist der Mechanismus, durch den der untergeordnete Prozess die Umgebungsvariablen seines übergeordneten Elements "erbt". (Das ist alles weitgehend, was andere Antworten hier gesagt hat)

Das heißt, ein Prozess nur je setzt seine eigenen Umgebungsvariablen.

Andere haben angegeben, ein Shell-Skript als eine Möglichkeit zum Setzen von Umgebungsvariablen im aktuellen Prozess zu verwenden, aber wenn Sie Variablen im aktuellen (Shell-) Prozess programmatisch setzen müssen, gibt es einen leicht indirekten Weg, der möglich ist .

Dieses betrachten:

% 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 
% 

Der integrierte in eval wertet ihr Argument als ob das Argument am Shell Aufforderung eingegeben wurden. Dies ist ein Sh-Style-Beispiel; Die Csh-Style-Variante bleibt als Übung übrig!

+0

Ich bemerkte, dass dies abgelehnt wurde. Irgendwelche Hinweise warum? Hat jemand einen Fehler entdeckt? –

+0

Ich bin mir nicht sicher, warum jemand dies ablehnen würde. Seltsam. Sieht nach einer guten Lösung für mich aus! – wasatchwizard

+0

Ich nehme an, weil die Antwort die Umgebungsvariable mit dem eingebauten Bash-Befehl 'eval' setzt, sind die Chancen, dass der Programmierer überhaupt nicht in der Lage ist, bash zu verwenden. Wenn der Programmierer ein Shell-Skript verwenden darf (was nicht immer der Fall ist, daher die Frage), gibt es andere offensichtliche und bessere Möglichkeiten, die Umgebungsvariable anders als das Bash-spezifische Eval zu setzen. (p.s. Ich habe nicht downvote) –