std.env — Umgebung und Kommandozeile

Zurück zur Unit-Übersicht

Zugriff auf Umgebungsvariablen und Kommandozeilenargumente — beides direkt aus dem Startstack, ohne C-Bibliothek. Der Kernel legt beim Prozessstart hinter argv den Zeigervektor der Umgebung ab; std.env liest ihn dort aus.

Einsatzbereiche: CLI-Werkzeuge, Dienste und Skript-Wrapper, die ihre Konfiguration aus –flag=wert oder Umgebungsvariablen beziehen.

Autor: Andreas Röne
Copyright: 2024–2025 Andreas Röne
Quelle: std/env.lyx

<WRAP info> std.env ist die Grundlage für die Umgebungsfunktionen in std.os: env_get ruft intern EnvLookupRaw auf. Wer nur lesen will, kommt mit std.env aus; wer Werte zur Laufzeit setzen will, braucht std.os — siehe Zusammenspiel mit std.os. </WRAP>

Import

import std.env;


Funktionen

Umgebungsvariablen

Signatur Beschreibung
EnvLookupRaw(name: pchar): pchar Wert der Variablen name, oder 0 wenn nicht gesetzt. Der Zeiger zeigt in die Umgebung, es wird nichts kopiert
EnvBase(): int64 Adresse des envp-Vektors, oder 0 wenn argv nicht gesichert wurde
EnvEntryValueOff(entry: pchar, key: pchar): int64 Prüft einen Eintrag der Form NAME=WERT gegen key; liefert den Offset des Werts im Eintrag oder -1

EnvBase und EnvEntryValueOff sind die Bausteine von EnvLookupRaw und im Alltag selten nötig — sie sind öffentlich, damit man eigene Durchläufe über die gesamte Umgebung schreiben kann.

 
Auch unter Windows nutzbar. EnvBase unterstellte das SysV-Speicherbild (envp hinter argv); beim Ziel win64 stürzte EnvLookupRaw deshalb sofort ab — samt allem, was darauf aufsetzt (env_get aus std.os, die Zeitzonenauswahl in std.datetime). Seit lyxc 1.1.3F wird dort der Windows-Umgebungsblock gelesen (#1677); nachgemessen mit einem PE unter Wine.

Kommandozeile

Signatur Beschreibung
ArgvGetStr(argc: int64, argv: pchar, name: pchar): pchar Sucht ein Argument der Form –name=wert und gibt den Wertteil zurück, sonst 0

Dazu die Compiler-Builtins, die den Startstack bereitstellen:

Builtin Beschreibung
GetArgC(): int64 Anzahl der Argumente einschließlich Programmname
GetArgV(): pchar Basis des argv-Zeigervektors
ArgvGet(argv: pchar, i: int64) Argument i; außerhalb von 0…argc kommt der Nullzeiger zurück

Beispiele

Umgebungsvariablen lesen

import std.env;

fn zeigVar(name: pchar): void {
    var v: pchar := EnvLookupRaw(name);
    if (v != 0 as pchar) { PrintLn("  ", name, " = ", v); }
    else                 { PrintLn("  ", name, " ist nicht gesetzt"); }
}

fn main(): int64 {
    zeigVar("HOME");
    zeigVar("LANG");
    zeigVar("GIBTESNICHT_XYZ");

    // Praefixe schlagen nicht faelschlich an
    zeigVar("HOM");
    zeigVar("HOMEX");
    return 0;
}

Ausgabe:

HOME = /home/andreas
  LANG = de_DE.UTF-8
  GIBTESNICHT_XYZ ist nicht gesetzt
  HOM ist nicht gesetzt
  HOMEX ist nicht gesetzt

Der Vergleich ist exakt: HOM schlägt bei einem Eintrag HOME=… nicht an, weil hinter dem Namen zwingend ein = stehen muss. Werte dürfen Leerzeichen enthalten — der Eintrag endet erst am Nullbyte.

Nicht gesetzt wird durch den Nullzeiger angezeigt, nicht durch einen leeren String. Eine gesetzte, aber leere Variable (FOO=) liefert einen gültigen Zeiger auf einen leeren String — der Unterschied ist also erkennbar.

Kommandozeilenargumente auswerten

import std.env;

fn hole(name: pchar, standard: pchar): pchar {
    var v: pchar := ArgvGetStr(GetArgC(), GetArgV(), name);
    if (v == 0 as pchar) { return standard; }
    return v;
}

fn main(): int64 {
    PrintLn("Aufruf mit ", IntToStr(GetArgC()), " Argumenten:");
    var i: int64 := 0;
    while (i < GetArgC()) {
        PrintLn("  argv[", IntToStr(i), "] = ", ArgvGet(GetArgV(), i) as pchar);
        i := i + 1;
    }

    PrintLn("Konfiguration:");
    PrintLn("  Ausgabedatei: ", hole("output", "a.out"));
    PrintLn("  Stufe:        ", hole("level", "1"));
    PrintLn("  Modus:        ", hole("mode", "standard"));
    return 0;
}

Aufruf ./d2 –output=bericht.pdf –level=3:

Aufruf mit 3 Argumenten:
  argv[0] = ./d2
  argv[1] = --output=bericht.pdf
  argv[2] = --level=3
Konfiguration:
  Ausgabedatei: bericht.pdf
  Stufe:        3
  Modus:        standard

Das Muster hole(name, standard) ist die übliche Form: ArgvGetStr liefert 0 bei fehlendem Argument, der Aufrufer setzt den Vorgabewert ein.


Zusammenspiel mit std.os

std.os bietet env_get, env_set, env_unset und env_has. Der Lesepfad landet bei EnvLookupRaw; Schreiben geht dagegen nicht in den Startstack, sondern in eine prozesseigene Überlagerung, die env_get vorgeschaltet ist.

import std.env;
import std.os;

fn main(): int64 {
    PrintLn("env_get(HOME)        = ", env_get("HOME"));
    PrintLn("EnvLookupRaw(HOME)   = ", EnvLookupRaw("HOME"));

    PrintLn("env_has(MEINE_VAR)   = ", IntToStr(env_has("MEINE_VAR") as int64));
    env_set("MEINE_VAR", "gesetzt-zur-laufzeit");
    PrintLn("nach env_set:");
    PrintLn("  env_get(MEINE_VAR)      = ", env_get("MEINE_VAR"));
    var raw: pchar := EnvLookupRaw("MEINE_VAR");
    PrintLn("  EnvLookupRaw(MEINE_VAR) gesetzt? ", IntToStr((raw != 0 as pchar) as int64), "   <- Ueberlagerung nicht sichtbar");

    env_unset("HOME");
    PrintLn("nach env_unset(HOME):");
    PrintLn("  env_get(HOME)      = '", env_get("HOME"), "'");
    PrintLn("  EnvLookupRaw(HOME) = '", EnvLookupRaw("HOME"), "'   <- Startstack unveraendert");
    return 0;
}

Ausgabe:

env_get(HOME)        = /home/andreas
EnvLookupRaw(HOME)   = /home/andreas
env_has(MEINE_VAR)   = 0
nach env_set:
  env_get(MEINE_VAR)      = gesetzt-zur-laufzeit
  EnvLookupRaw(MEINE_VAR) gesetzt? 0   <- Ueberlagerung nicht sichtbar
nach env_unset(HOME):
  env_get(HOME)      = ''
  EnvLookupRaw(HOME) = '/home/andreas'   <- Startstack unveraendert

Daraus folgen drei Regeln:

  • Wer mit env_set arbeitet, muss durchgängig env_get lesen — EnvLookupRaw sieht die Überlagerung nicht.
  • env_unset entfernt nichts aus dem Startstack, es blendet den Namen nur für env_get aus.
  • Ein per execve gestartetes Kind erbt die Überlagerung nicht — es bekommt die unveränderte Umgebung des Elternprozesses.

Unterschiedlich ist auch der Rückgabewert bei fehlender Variable: EnvLookupRaw liefert den Nullzeiger, env_get einen leeren String. Bei env_get sind „nicht gesetzt„ und „auf leer gesetzt“ daher nicht unterscheidbar; dafür gibt es env_has.


Fallstricke

Geprüft mit lyxc 1.0.21A.

Argumentschleifen enden am Nullzeiger

argv[argc] ist der abschließende Nullzeiger — die verlässliche Abbruchbedingung. Seit dem Fix von #1460 liefert auch jeder Index darüber hinaus 0, statt in die dahinterliegende Umgebung zu lesen:

argc = 2
argv[argc]   = 0
argv[argc+1] = 0

Ein Off-by-one führt damit zu einem Nullzeiger statt zu einer Zeichenkette aus der Umgebung. Schleifen trotzdem gegen GetArgC() begrenzen — das ist die klarere Absicht.

Der Rückgabewert zeigt in die Umgebung

EnvLookupRaw kopiert nicht. Der Zeiger bleibt gültig, solange der Prozess lebt — die Startstack-Umgebung wird nicht verändert. Wer den Wert aber selbst umschreiben will, muss ihn vorher kopieren; ein poke8 auf den Rückgabewert verändert die Umgebung des laufenden Prozesses.

ArgvGet in PrintLn braucht einen Cast

Ohne as pchar gibt PrintLn(ArgvGet(GetArgV(), i)) die Zeigeradresse als Zahl aus:

argv[0] = 140721192761205

Mit ArgvGet(GetArgV(), i) as pchar erscheint der Text. Das betrifft nur die Ausgabe; ArgvGetStr und StrLen verarbeiten den Wert auch ohne Cast korrekt.

Der Flag-Name wird ohne führende Striche übergeben

ArgvGetStr(argc, argv, „output“) findet –output=…. Die beiden Striche prüft die Funktion selbst — ArgvGetStr(argc, argv, „–output“) findet folglich nur —-output=… und damit praktisch nichts. Frühere Fassungen dieser Seite zeigten die Form mit Strichen.

Nur --name=wert, nichts anderes

Nicht unterstützt: getrennte Form (–output datei), Kurzformen (-o wert), Schalter ohne Wert (–verbose) und die Endemarke . –name= mit leerem Wert liefert einen gültigen Zeiger auf einen leeren String, nicht 0. Wer mehr braucht, wertet argv selbst aus.

Obergrenze von 8192 Einträgen

EnvLookupRaw bricht nach 8192 Umgebungseinträgen ab und meldet „nicht gesetzt„. In der Praxis unkritisch — die üblichen Grenzen des Kernels für Umgebungsgröße greifen weit vorher.


Verwandte Units

  • std.osenv_get/env_set/env_unset/env_has, Arbeitsverzeichnis, Prozess-IDs
  • std.stringStrSub, StrLen für die Nachbearbeitung der Werte
  • std.conv — Argumentwerte in Zahlen wandeln

Letzte Aktualisierung: 2026-08-19 — Hinweis zum Windows-Umgebungsblock ergänzt (#1677).