Skip to content

Umgebungsvariablen und PATH

💡 Lernleitfaden: Jedes Mal, wenn Sie im Terminal git oder python eingeben, muss das System suchen, wo sich dieses Programm befindet. Jedes Mal, wenn Ihr Code eine Large-Language-Model-API aufruft, muss das Programm wissen, welcher Schlussel verwendet werden soll. Hinter beiden Aufgaben steckt derselbe Mechanismus — Umgebungsvariablen.


0. Jedes Programm tragt eine Reihe von Konfigurationen bei sich

Jedes laufende Programm halt einen Satz von "Schlussel=Wert"-Konfigurationen, die als Umgebungsvariablen bezeichnet werden. Das Programm kann diese Konfigurationen jederzeit lesen, um die aktuelle Ausfuhrungsumgebung zu erfahren.

Klicken Sie auf eine beliebige Variable in der Liste unten, um ihren Wert im Terminal zu "betrachten":

Environment Variable BrowserClick any variable row to inspect its value and purpose in the terminal
VariableExample value
HOME/Users/alice
USERalice
SHELL/bin/zsh
PATH/usr/local/bin:/usr/bin:/bin
PWD/Users/alice/projects
LANGen_US.UTF-8
NODE_ENVdevelopment
OPENAI_API_KEYsk-••••••••••••••••
bash
← Click any variable on the left to inspect it
$
Core concept:Environment variables are key=value configuration owned by each process. A program inherits a copy from its parent process at startup. You can inspect them with echo $VARIABLE and set them with export KEY=value.

1. PATH: Wie die Shell Ihre eingegebenen Befehle findet

PATH ist eine besondere Umgebungsvariable, die eine Reihe von Verzeichnispfaden (doppelpunktgetrennt) speichert. Wenn Sie git eingeben, durchsucht die Shell diese Verzeichnisse in der angegebenen Reihenfolge nach einer ausfuhrbaren Datei namens git — sie stoppt beim ersten Treffer.

bash
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Wahlen Sie einen Befehl und beobachten Sie, wie die Shell Verzeichnis fur Verzeichnis sucht:

PATH Search ProcessEnter a command name and see how the shell searches directories
Choose command:
Current PATH:
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
/usr/local/bin
Waiting
/usr/bin
Waiting
/bin
Waiting
/usr/sbin
Waiting
/sbin
Waiting
Core mechanism:After the shell receives a command name, it searches directories in PATH order. The first match wins and the search stops. That makes PATH order important: earlier directories have higher priority.

Drei Schlusselregeln:

  • Je weiter vorne ein Verzeichnis im PATH steht, desto hoher die Prioritat
  • Beim ersten Treffer wird gestoppt, die Suche wird nicht fortgesetzt
  • Keines der Verzeichnisse enthalt den Befehl → command not found

2. Warum muss das Terminal nach der Installation eines Tools neu gestartet werden?

Bei der Installation von Tools wie nvm, Homebrew oder conda fugt das Installationsskript automatisch eine Zeile zu ~/.zshrc hinzu, um sein eigenes Verzeichnis zum PATH hinzuzufugen:

bash
# Vom Installationsskript automatisch geschriebener Inhalt (Beispiel)
export PATH="/usr/local/opt/python@3.12/bin:$PATH"

Diese Codezeile wird nur beim Start einer neuen Shell ausgefuhrt. Bereits geoffnete Terminalfenster sind davon nicht betroffen, deshalb:

bash
# Auch ohne Neustart sofort wirksam
source ~/.zshrc

Haufige Situationen mit KI-Entwicklungstools:

bash
# Ollama / pipx zeigen nach der Installation command not found
which ollama          # Tatsachlichen Installationsort finden

# Pfad der per pip installierten CLI-Tools (zum PATH hinzufugen)
# macOS: ~/Library/Python/3.x/bin
# Linux: ~/.local/bin
export PATH="$PATH:$HOME/.local/bin"

# Empfohlen: CLI-Tools mit pipx installieren, verwaltet PATH automatisch
pipx install aider-chat

3. Gultigkeitsbereich von Variablen: Wer kann diese Variable sehen?

Umgebungsvariablen werden nicht an alle Programme gesendet — jeder Prozess halt eine eigene Kopie, die vom Elternprozess geerbt wurde. Änderungen an der eigenen Kopie beeinflussen den Elternprozess nicht.

Das folgende Diagramm zeigt drei Ebenen. Exportieren Sie eine neue Variable auf der "Benutzerebene" und prufen Sie, ob sie auf der "Prozessebene" erscheint:

Three Levels of Environment VariablesVariables flow one way from outer scopes to inner scopes; child processes inherit a copy from parents
🖥️
System level /etc/environment
Visible to all users and processes; configured by an administrator
PATH=/usr/local/bin:/usr/bin:/bin
LANG=zh_CN.UTF-8
TZ=Asia/Shanghai
▼ Child process inherits the parent environment
👤
User level ~/.zshrc
Affects only the current user and is loaded when the login shell starts
HOME=/Users/alice
SHELL=/bin/zsh
NVM_DIR=$HOME/.nvm
=
▼ Start a child process, such as node app.js
⚙️
Process level (currently running program)
Inherits variables from upper levels, disappears on exit, and does not modify the parent process
PATH=/usr/local/bin:/usr/bin:/bin
LANG=zh_CN.UTF-8
TZ=Asia/Shanghai
HOME=/Users/alice
SHELL=/bin/zsh
NVM_DIR=$HOME/.nvm
NODE_ENV=development
PORT=3000
One-way flow:Variables are inherited downward only. Changing a variable in a child process does not affect its parent. Variables set with export in a terminal also disappear when that terminal closes.

4. export: Bestimmt, ob ein Kindprozess diese Variable lesen kann

Beim Setzen einer Variablen ist es ein grundlegend anderer Vorgang, ob Sie export hinzufugen oder nicht:

export Decides Whether Child Processes Can See a VariableToggle the switch and observe whether the child process can read a variable set by the parent
Parent process (Shell)
$MY_VAR="hello"
$echo $MY_VAR
hello
$bash -c 'echo $MY_VAR'
Start child process
Variable not inherited
Child process (bash -c ...)
$echo $MY_VAR
(empty output)
#A child process cannot modify parent variables
Without export: The variable exists only in the current shell, so the child process reads an empty string.

Damit eine Variable sitzungsuebergreifend dauerhaft erhalten bleibt, schreiben Sie den export-Befehl in eine Konfigurationsdatei:

bash
# macOS (zsh)
echo 'export MY_VAR="value"' >> ~/.zshrc
source ~/.zshrc       # Sofort wirksam, kein Terminalneustart notig

# Linux (bash)
echo 'export MY_VAR="value"' >> ~/.bashrc
source ~/.bashrc

5. API-Schlussel: Durfen niemals im Code stehen

Beim Aufruf von APIs wie OpenAI, Anthropic oder DeepSeek ist der Schlussel Ihr "Ausweis + Kreditkarte". Wird er geleakt, konnen andere Ihr Kontingent aufbrauchen — die Kosten tragen Sie.

Der haufigste Fehler ist, den Schlussel direkt im Code zu hinterlegen:

Hard-coded Keys vs Environment VariablesThe same feature, two implementations, completely different security outcomes
Dangerous: key written in code
# Python
import openai
 
client = openai.OpenAI(
api_key="sk-proj-abc123..."
)
💀After git push, the key is public on GitHub
💀Crawlers can find it quickly and generate costs
💀GitHub Secret Scanner may revoke the key automatically
💀Deleting the commit is not enough because Git history keeps it
Correct: read from environment variable
# Python
import openai, os
 
client = openai.OpenAI(
api_key=os.environ.get("OPENAI_API_KEY")
)
The code contains no secret and can be open-sourced safely
Development, testing, and production can use different keys
If a key leaks, regenerate it without changing code
Team members can use separate keys without affecting each other
Golden rule:A secret string in code means the secret is already leaked. GitHub Secret Scanner can detect prefixes such as sk- shortly after a push and notify providers to revoke them. Even if you delete the commit, Git history still contains it.

6. Lokale Entwicklung: Schlussel mit .env-Dateien verwalten

Bei der lokalen Entwicklung speichern Sie Schlussel in einer .env-Datei im Projektverzeichnis. Der Code liest sie uber die dotenv-Bibliothek ein. .env muss zwingend zu .gitignore hinzugefugt und nicht in Git committet werden.

Schreiben Sie links die Konfiguration und lesen Sie sie rechts — wechseln Sie die Sprache, um zwei verschiedene Schreibweisen zu sehen:

.env File + Code ReadingConfiguration on the left, code on the right; the variable name is the only link
📄 .env Do not commit
# Local development config, do not commit to Git
OPENAI_API_KEY=sk-proj-abc123...
DATABASE_URL=postgresql://localhost/dev
PORT=3000
NODE_ENV=development
📋 .env.example Can commit
# Copy to .env and fill in real values
OPENAI_API_KEY=(leave empty)
DATABASE_URL=(leave empty)
PORT=(leave empty)
NODE_ENV=(leave empty)
💻 main.py
# pip install python-dotenv openai
from dotenv import load_dotenv
import os, openai
 
load_dotenv() # Read .env file
 
client = openai.OpenAI(
api_key=os.environ.get("OPENAI_API_KEY")
)
 
db = os.environ.get("DATABASE_URL")
port = int(os.environ.get("PORT", 8000))
Values actually read by the program
OPENAI_API_KEYsk-proj-abc123...
DATABASE_URLpostgresql://localhost/dev
PORT3000
Workflow:load_dotenv() / import 'dotenv/config' reads the .env file at startup, injects its key-value pairs into the process environment, and the code reads them with os.environ or process.env. The two sides are connected only by variable names.

7. Produktionsumgebung: Die Laufzeitumgebung Schlussel injizieren lassen

.env ist ein Hilfsmittel fur die Entwicklungsphase. Auf Servern und Cloud-Plattformen sollte die Laufzeitumgebung fur die Injektion der Schlussel verantwortlich sein — der Code selbst sollte nicht wissen, wo die Schlussel gespeichert sind:

How Production Injects Secrets.env is a development convenience; servers should not rely on it
/etc/systemd/system/myapp.service
# Recommended: use a separate secret file with controlled permissions
[Service]
EnvironmentFile=/etc/myapp/secrets.env
ExecStart=/usr/bin/node /app/index.js
# Set file permissions so only the owner can read it
sudo chmod 600 /etc/myapp/secrets.env
sudo chown deploy:deploy /etc/myapp/secrets.env
# Reload configuration and restart the service
sudo systemctl daemon-reload
sudo systemctl restart myapp
After chmod 600, only the deploy user can read the secret file; other accounts cannot access it
Secrets are separated from code, so rotating a key does not require redeploying code
Avoid writing Environment="KEY=val" directly in the systemd file; it requires reloads and leaves plaintext in config
Principle:.env files are convenient for local development. In production, the runtime platform should inject environment variables, while application code stays unaware of where secrets live or how they arrived.

8. Praktische Fehlerbehebung

command not found

bash
# Schritt 1: Prufen, ob im PATH vorhanden
which python3         # Ausgabe vorhanden = gefunden

# Schritt 2: Tatsachlichen Programmstandort finden (macOS)
brew list python | grep bin

# Schritt 3: Verzeichnis zum PATH hinzufugen
export PATH="/gefundener/pfad:$PATH"
source ~/.zshrc       # Nach dem Schreiben in die Konfigurationsdatei source ausfuhren

Zwei Versionen installiert, aber nicht die gewunschte wird verwendet

bash
which python
# /usr/bin/python ← Alte Systemversion, weiter vorne im PATH

# Neues Verzeichnis an den Anfang des PATH setzen
export PATH="/usr/local/bin:$PATH"

which python
# /usr/local/bin/python ← Neue Version, jetzt priorisiert

Variable ist eindeutig gesetzt, aber das Programm liest sie nicht

UrsacheLosung
export vergessenexport hinzufugen und erneut versuchen
~/.zshrc geandert, aber nicht wirksamsource ~/.zshrc
.env verwendet, aber dotenv nicht installiertpip install python-dotenv / npm install dotenv
Auf dem Server nur in der SSH-Sitzung gultigStattdessen systemd EnvironmentFile verwenden

Glossar

BegriffBedeutung
PATHSpeichert die Liste der Verzeichnisse, in denen die Shell nach ausfuhrbaren Dateien sucht, doppelpunktgetrennt, Reihenfolge bestimmt die Prioritat
exportMarkiert eine Variable als vererbbar, Kindprozesse erhalten beim Start automatisch eine Kopie
sourceFuhrt eine Konfigurationsdatei in der aktuellen Shell erneut aus, um Änderungen sofort zu ubernehmen
whichZeigt den Pfad zur ausfuhrbaren Datei eines Befehls an (Ergebnis der PATH-Suche)
.envLokale Projektkonfigurationsdatei, speichert Entwicklungsschlussel, muss zwingend zu .gitignore hinzugefugt werden
.env.exampleVorlage mit vollstandigen Variablennamen aber leeren Werten, kann sicher in Git committet werden
chmod 600Dateiberechtigung: Nur der Eigentumer darf lesen und schreiben, geeignet zum Schutz von Schlusseldateien
Secret ScannerAutomatischeScan-Funktion auf Plattformen wie GitHub, die Schlussel-Lecks erkennt und den Anbieter zur Sperrung benachrichtigt