Die Shell-Umgebung ist mehr als die Summe ihrer Variablen. Sie umfasst alles, was deine Sitzung definiert: Variablen, Aliases, Funktionen, History, das aktuelle Verzeichnis und die offenen Datei-Deskriptoren. Wer versteht, wann welche Init-Datei gelesen wird und wo persistente Konfiguration hingehört, vermeidet die häufigste Frustration auf der Kommandozeile — dass Änderungen nach dem nächsten Login wieder weg sind.

Was ist die Shell-Umgebung?

Wenn du ein Terminal öffnest, startet ein Shell-Prozess. Dieser Prozess hat einen eigenen Kontext, der zusammen die Shell-Umgebung bildet. Sie besteht aus mehreren Komponenten, die du dir wie ein Inventar der laufenden Sitzung vorstellen kannst.

KomponenteBeschreibung
VariablenLokale Shell-Variablen und exportierte Umgebungsvariablen wie HOME, PATH, USER
AliasesKurzformen für längere Befehle, etwa ll für ls -la
FunktionenSelbstdefinierte Shell-Funktionen mit Logik und Argumenten
HistoryListe der zuletzt eingegebenen Befehle, meist in ~/.bash_history
Working DirectoryDas aktuelle Verzeichnis, abrufbar mit pwd
Datei-DeskriptorenOffene Verbindungen zu stdin, stdout, stderr und weiteren Streams

Wer erzeugt diese Umgebung? Beim Start liest die Shell eine Reihe von Init-Files — Konfigurationsdateien wie .bashrc oder .bash_profile — und führt sie der Reihe nach aus. Diese Skripte setzen Variablen, definieren Aliases und laden Funktionen. Welche Datei gelesen wird, hängt davon ab, wie die Shell gestartet wurde.

Login-, Interactive- und Non-Interactive-Shell

Die Bash unterscheidet zwei orthogonale Eigenschaften: Login vs. Non-Login und Interactive vs. Non-Interactive. Daraus ergeben sich vier Kombinationen, die jeweils unterschiedliche Init-Files lesen.

VarianteWann tritt sie auf?Gelesene Init-Files (Bash)
Login + Interactivetty-Login, SSH-Verbindung, bash -l, macOS-Terminal-Tab (historisch)/etc/profile, dann erste vorhandene aus ~/.bash_profile, ~/.bash_login, ~/.profile
Non-Login + InteractiveNeues Terminal-Tab unter Linux, bash in laufender Sitzung/etc/bash.bashrc, ~/.bashrc
Login + Non-InteractiveSelten, etwa ssh host -- befehl mit erzwungenem Loginwie Login + Interactive, aber ohne Prompt
Non-Login + Non-InteractiveShell-Skripte mit #!/bin/bash, Cron-JobsNur BASH_ENV, falls gesetzt — keine Init-Files

Die wichtigste Konsequenz: Cron-Jobs und Skripte sehen deine Aliases nicht. Aliases werden nur in interaktiven Shells eingelesen. Ähnlich frustrierend ist, dass eine SSH-Sitzung manchmal andere Variablen sieht als ein lokales Terminal — denn SSH öffnet eine Login-Shell, ein typisches Linux-Terminal aber eine Non-Login-Interactive-Shell.

So findest du heraus, in welcher Variante du gerade steckst:

Bash Shell-Variante prüfen
shopt -q login_shell && echo "Login-Shell" || echo "Non-Login-Shell"
[[ $- == *i* ]] && echo "Interactive" || echo "Non-Interactive"

Init-Files: bashrc, bash_profile, profile

Die Init-Files liegen in deinem Home-Verzeichnis und im Systemverzeichnis /etc. Sie werden von der Shell beim Start ausgeführt und konfigurieren so deine Umgebung.

DateiWann gelesenTypischer Inhalt
/etc/profileLogin-Shell, systemweitPATH, umask, systemweite Variablen
/etc/profile.d/*.shÜber /etc/profile eingebundenModulare Pakete, etwa bash_completion
~/.bash_profileLogin-Shell, benutzerspezifischLogin-spezifische Variablen, oft nur Wrapper für .bashrc
~/.bash_loginLogin-Shell, falls .bash_profile fehltSelten verwendet, gleicher Zweck wie .bash_profile
~/.profileLogin-Shell, falls keine der beiden oben existiertPOSIX-kompatibler Fallback, auch von dash und sh gelesen
/etc/bash.bashrcInteractive Non-Login, systemweit (Debian/Ubuntu)Systemweite Aliases, Prompt-Defaults
~/.bashrcInteractive Non-Login, benutzerspezifischAliases, Funktionen, Prompt, Shell-Optionen
~/.bash_logoutBeim Verlassen einer Login-ShellAufräumarbeiten, Cache leeren

Die übliche Empfehlung lautet: Alles Interaktive in ~/.bashrc, und ~/.bash_profile als Wrapper, der ~/.bashrc einbindet. Damit funktioniert deine Konfiguration sowohl beim lokalen Terminal als auch nach SSH-Login identisch.

Bash ~/.bash_profile als Wrapper
# Login-spezifische Variablen
export PATH="$HOME/.local/bin:$PATH"

# Interaktive Konfiguration einbinden
if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
fi

Zsh hat eine ähnliche, aber nicht identische Aufteilung: ~/.zshenv (immer), ~/.zprofile (Login), ~/.zshrc (Interactive), ~/.zlogin (Login, nach .zshrc). Auf macOS ist Zsh seit Catalina die Standard-Shell.

Variablen anzeigen und setzen

Die Shell unterscheidet zwischen Shell-Variablen (nur in der aktuellen Shell sichtbar) und Umgebungsvariablen (an Kind-Prozesse vererbt). Die wichtigsten Befehle dafür kennst du vielleicht schon — hier der Überblick im Kontext der Umgebung.

BefehlZweck
envZeigt alle exportierten Umgebungsvariablen
printenvWie env, aber kann auch eine einzelne Variable abfragen: printenv HOME
setZeigt alle Shell-Variablen, Funktionen und Optionen — deutlich mehr als env
export VAR=wertSetzt eine Umgebungsvariable, sichtbar für Kind-Prozesse
VAR=wertSetzt nur eine lokale Shell-Variable
unset VAREntfernt eine Variable komplett
declare -p VARZeigt Typ und Wert einer Variable im Detail

Ein praktischer Test der Differenz:

Bash Shell- vs. Umgebungsvariable
lokal="nur hier"
export global="auch im Kind"
bash -c 'echo "lokal=$lokal global=$global"'
Output
lokal= global=auch im Kind

Details zur Variablen-Syntax, Sonderzeichen wie $?, $# und Quoting findest du im Artikel Variablen.

Wichtige Standard-Umgebungsvariablen

Diese Variablen sind auf praktisch jedem Unix-System gesetzt. Programme verlassen sich darauf — ein falsch gesetztes LANG oder TERM führt schnell zu kaputtem Output.

VariableBedeutungWo gesetzt
HOMEPfad zum Home-Verzeichnis des UsersLogin-Prozess
USER, LOGNAMEAktueller BenutzernameLogin-Prozess
SHELLPfad zur Login-Shell (aus /etc/passwd)Login-Prozess
PATHSuchpfade für ausführbare Programme/etc/profile, ~/.profile
PWDAktuelles ArbeitsverzeichnisShell, automatisch
OLDPWDVorheriges Verzeichnis, Ziel von cd -Shell, automatisch
EDITORStandard-Editor für Tools wie git commit oder crontab -e~/.bashrc oder ~/.profile
VISUALWie EDITOR, aber für vollwertige Editoren statt Zeileneditoren~/.bashrc
PAGERStandard-Pager, meist less~/.bashrc
LANGSprach- und Locale-Einstellung, etwa de_DE.UTF-8/etc/locale.conf, /etc/default/locale
LC_*Feinkontrolle einzelner Locale-Aspekte (Zeit, Zahlen, Sortierung)wie LANG
TERMTerminal-Typ, etwa xterm-256colorTerminal-Emulator beim Start
TZZeitzone, etwa Europe/Berlinoptional, sonst System-Default
TMPDIRVerzeichnis für temporäre Dateienoptional, meist /tmp
MANPATHSuchpfade für Manpagesman selbst, oder ~/.bashrc
XDG_CONFIG_HOMEBasis für User-Config, Default ~/.configXDG-konforme Anwendungen
XDG_DATA_HOMEBasis für User-Daten, Default ~/.local/shareXDG-konforme Anwendungen

Wenn du eine dieser Variablen dauerhaft setzen willst, gehört der export-Befehl in ~/.bashrc (für Interactive) oder ~/.profile (auch für GUI-Anwendungen, die kein Terminal öffnen).

Aliases

Ein Alias ist eine Kurzform für einen längeren Befehl. Aliases gelten nur in interaktiven Shells und werden nicht an Kind-Prozesse vererbt.

Bash Aliases definieren und nutzen
alias ll='ls -la'
alias gs='git status'
alias ..='cd ..'

# Alle Aliases anzeigen
alias

# Einen Alias entfernen
unalias ll

Damit Aliases dauerhaft verfügbar sind, gehören sie in ~/.bashrc. Manche Distributionen lagern sie in eine eigene Datei ~/.bash_aliases aus, die dann von ~/.bashrc eingebunden wird:

Bash Aliases auslagern
# In ~/.bashrc:
if [ -f ~/.bash_aliases ]; then
    . ~/.bash_aliases
fi

Wenn du einen Alias temporär umgehen willst — etwa weil ls als ls --color=auto aliasiert ist und du das Original brauchst — stell dem Befehl einen Backslash voran:

Bash Alias umgehen
\ls /etc

Alternativ funktionieren auch command ls oder /bin/ls.

Funktionen statt Aliases

Aliases sind eine reine Textersetzung am Zeilenanfang. Sobald du Argumente verarbeiten oder Logik einbauen willst, brauchst du eine Shell-Funktion. Funktionen sind sichtbar wie Aliases nur in der aktuellen Shell, lassen sich aber wie ein Befehl mit Argumenten aufrufen.

Bash Verzeichnis anlegen und reinwechseln
mkcd() {
    mkdir -p "$1" && cd "$1"
}

$1 ist das erste Argument. Mit mkcd projekt-x legst du jetzt das Verzeichnis an und wechselst direkt hinein. Funktionen gehören wie Aliases nach ~/.bashrc.

Faustregel: Alias für eine reine Abkürzung, Funktion sobald Argumente, Pipes oder mehrere Befehle ins Spiel kommen.

Persistente Konfiguration sauber organisieren

Eine ~/.bashrc kann schnell auf mehrere hundert Zeilen anwachsen — Aliases, Funktionen, Prompt-Konfiguration, Tool-Init-Skripte, alles bunt durcheinander. Sauberer ist eine modulare Struktur, bei der du themenspezifische Dateien in einem Unterverzeichnis ablegst und sie automatisch einbindest.

Bash Modulare ~/.bashrc
# In ~/.bashrc am Ende:
if [ -d ~/.bashrc.d ]; then
    for f in ~/.bashrc.d/*.sh; do
        [ -r "$f" ] && . "$f"
    done
    unset f
fi

Im Verzeichnis ~/.bashrc.d/ liegen dann Dateien wie 10-aliases.sh, 20-functions.sh, 30-prompt.sh, 40-tools.sh. Die Zahlen-Präfixe steuern die Lade-Reihenfolge. Alternativ verwenden manche Setups ~/.config/bash/ und folgen damit der XDG Base Directory Specification.

Spätestens wenn du diese Konfiguration auf mehreren Rechnern synchron halten willst, lohnt sich ein Blick auf Dotfiles-Verwaltung. Tools wie chezmoi, yadm oder ein einfaches Git-Repo mit Symlinks halten deine Shell-Umgebung über Hosts hinweg konsistent.

Häufige Fragen

Wo setze ich PATH-Erweiterungen?

In ~/.profile oder ~/.bash_profile, nicht in ~/.bashrc. Grund: GUI-Anwendungen und Login-Sessions lesen ~/.bashrc nicht, sondern nur die Login-Init-Files. Wenn du ~/.local/bin ergänzen willst, schreibe export PATH="$HOME/.local/bin:$PATH" in ~/.profile. Beim nächsten Login (oder nach source ~/.profile) ist der Pfad in der gesamten Sitzung verfügbar.

Warum sieht ssh meinen Alias nicht?

Aliases werden nur in interaktiven Shells eingelesen, und sie stehen üblicherweise in ~/.bashrc. Wenn du ssh host befehl aufrufst, startet eine nicht-interaktive Login-Shell, die ~/.bashrc überspringt. Lösung: Entweder den Befehl mit ssh -t host interaktiv ausführen, oder die nötigen Aliases in ~/.bash_profile definieren und vorher shopt -s expand_aliases setzen — Letzteres ist aber selten der Mühe wert.

Was passiert, wenn beide .profile und .bash_profile existieren?

Die Bash liest beim Login nur die erste vorhandene Datei in der Reihenfolge ~/.bash_profile, ~/.bash_login, ~/.profile. Existiert ~/.bash_profile, wird ~/.profile komplett ignoriert. Das ist eine häufige Falle: Du fügst etwas zu ~/.profile hinzu, aber ~/.bash_profile ist da und überschattet es. Prüfe mit ls -la ~/ | grep -E 'profile|bash', was tatsächlich existiert.

Warum wird die Shell-Variable in Skripten nicht erkannt?

Weil sie nicht exportiert ist. name=wert erzeugt nur eine Shell-Variable; ein Kind-Prozess wie ein Skript sieht sie nicht. Erst export name=wert (oder name=wert direkt vor dem Skript-Aufruf, etwa name=wert ./skript.sh) macht sie zur Umgebungsvariable und vererbt sie weiter.

Wie sehe ich, in welcher Shell-Variante ich gerade bin?

shopt -q login_shell && echo Login || echo Non-Login zeigt dir, ob es eine Login-Shell ist. Die Variable $- enthält die aktuellen Shell-Optionen — taucht dort ein i auf, ist die Shell interaktiv. Den Pfad der laufenden Shell findest du mit echo $0 (Shell-Name) oder ps -p $$ -o comm= (zuverlässiger bei Skripten).

Brauche ich source ~/.bashrc nach Änderungen?

Ja, wenn die Änderungen in der aktuellen Sitzung wirken sollen. Die Shell liest Init-Files nur beim Start. Mit source ~/.bashrc (oder kurz . ~/.bashrc) wird die Datei im Kontext der laufenden Shell ausgeführt, und neue Aliases, Variablen und Funktionen sind sofort verfügbar. Ein neues Terminal-Tab erledigt das automatisch.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Grundlagen

Zur Übersicht