Zum Inhalt springen

Variablen und Umgebung

Eine Variable setzt du in der Bash mit name=wert, ohne Leerzeichen um das Gleichheitszeichen, und liest sie mit $name. Es gibt aber zwei Sorten, und der Unterschied erklärt viele Rätsel:

  • Shell-Variablen gehören nur der laufenden Shell. Programme, die du startest, wissen nichts davon.
  • Umgebungsvariablen (environment variables) werden an jedes Programm vererbt, das die Shell startet. Dazu gehören HOME, PATH, LANG, USER.

Aus einer Shell-Variable wird mit export eine Umgebungsvariable:

flowchart TD
    S["Deine Bash<br/>farbe=blau (Shell-Variable)<br/>export EDITOR=vim (Umgebung)"]
    S -->|startet| P1["Programm, z.B. git<br/>sieht EDITOR, aber nicht farbe"]
    S -->|startet| P2["Skript ./test.sh<br/>sieht EDITOR, aber nicht farbe"]

Hands-on: Eine zweite Bash als Kindprozess ist der einfachste Test.

Terminal-Fenster
farbe=blau
echo "$farbe"
bash -c 'echo "Kind sieht: $farbe"'
export farbe
bash -c 'echo "Kind sieht: $farbe"'
export EDITOR=vim
env | grep -E '^(farbe|EDITOR)='

Was erwartest du? Beim ersten Kindprozess ist die Ausgabe leer, nach export steht blau da. env und printenv listen alle Umgebungsvariablen, printenv HOME eine einzelne. Eine Variable nur für einen einzigen Aufruf setzt du vor den Befehl: LANG=C date gibt das Datum auf Englisch aus, ohne deine Shell zu ändern.

Konvention: Umgebungsvariablen schreibt man gross (PATH), eigene Shell-Variablen in Skripten klein (anzahl). So kollidieren sie nicht.

Variable Inhalt
HOME Dein Home-Verzeichnis, dasselbe wie ~
USER Dein Benutzername
PATH Suchpfad für Befehle
PWD Aktuelles Verzeichnis, wie pwd
SHELL Deine Login-Shell
LANG Sprache und Zeichensatz, etwa de_CH.UTF-8
EDITOR Editor, den git, crontab -e und andere aufrufen
PS1 Aussehen des Prompts
HISTSIZE Anzahl Befehle, die history behält
$? Exit-Status des letzten Befehls (keine Umgebungsvariable)
$$ Prozess-ID der Shell

Variablen, die du im Terminal setzt, sind beim nächsten Login weg. Damit Einstellungen bleiben, trägst du sie in eine Startdatei ein. Welche die Bash liest, hängt davon ab, wie sie gestartet wurde:

Datei Gelesen von Typischer Inhalt
/etc/profile Login-Shells, systemweit PATH für alle, umask
~/.profile Login-Shells, persönlich Umgebungsvariablen, ~/bin in den PATH
/etc/bash.bashrc interaktiven Shells, systemweit Prompt, Vervollständigung
~/.bashrc interaktiven Shells, persönlich Aliase, Funktionen, Prompt, History
~/.bash_aliases von Ubuntus ~/.bashrc eingebunden deine Aliase und Funktionen

Eine Login-Shell entsteht bei der Anmeldung an der Konsole oder per SSH. Eine interaktive Shell ist jedes Terminalfenster, das du danach öffnest. Auf Ubuntu musst du dich darum nicht kümmern: ~/.profile lädt am Ende ~/.bashrc, und ~/.bashrc lädt ~/.bash_aliases, falls die Datei existiert. Praktische Regel:

  • Umgebungsvariablen wie EDITOR oder PATH-Ergänzungen nach ~/.profile.
  • Alles andere (Aliase, Funktionen, Prompt) nach ~/.bash_aliases.

~/.bashrc enthält bereits einen Block, der ~/.bash_aliases einliest. ~/.profile fügt ~/bin und ~/.local/bin zum PATH hinzu, wenn sie beim Login existieren.

source: eine Datei in der laufenden Shell ausführen

Abschnitt betitelt „source: eine Datei in der laufenden Shell ausführen“

Nach einer Änderung an ~/.bash_aliases willst du nicht jedes Mal ein neues Terminal öffnen. source datei (oder kurz . datei) führt die Datei in der aktuellen Shell aus. Würdest du sie wie ein Skript mit bash datei starten, liefe sie in einem Kindprozess und alle Definitionen wären danach wieder weg, aus demselben Grund, aus dem cd ein Builtin sein muss.

Terminal-Fenster
source ~/.bash_aliases
. ~/.bash_aliases

Ein Alias ist eine Abkürzung für einen längeren Befehl. Ubuntu bringt schon einige mit:

Terminal-Fenster
alias
alias ll='ls -alF'
alias ..='cd ..'
alias hist='history | grep -i'
ll
hist mkdir
unalias ..
\ls

alias ohne Argumente zeigt alle, unalias löscht einen. Der Backslash vor \ls umgeht den Alias einmalig und startet das echte Programm. Alles, was nach dem Alias auf der Zeile steht, wird angehängt, darum funktioniert hist mkdir. Ein paar Beispiele aus der Praxis:

~/.bash_aliases
# Sicherheitsnetz: nachfragen vor dem Überschreiben
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Kürzer tippen
alias ll='ls -alF'
alias la='ls -A'
alias ..='cd ..'
alias ...='cd ../..'
# Suchen
alias hist='history | grep -i'
alias fp='ps -ef | grep -v grep | grep -i'
# Manpages in einer bestimmten Sprache
alias mande='LANG=de_CH.UTF-8 man'
alias manen='LANG=en_US.UTF-8 man'

Ein Alias kann nur Text anhängen. Sobald ein Argument mitten im Befehl stehen soll, brauchst du eine Funktion. Innerhalb der Funktion heissen die Argumente $1, $2 und so weiter, "$@" sind alle zusammen.

~/.bash_aliases
alias manen='LANG=en_US.UTF-8 man'
# Verzeichnis anlegen und gleich hineinwechseln
mkcd() {
mkdir -p "$1" && cd "$1" || return
}
# Datei mit Zeitstempel sichern: sichern config.txt -> config.txt.2026-11-05
sichern() {
cp -v "$1" "$1.$(date +%F)"
}
# Manpage als PDF öffnen (braucht ghostscript)
manpdf() {
local pdf="/tmp/$1.pdf"
man -t "$1" | ps2pdf - "$pdf" && xdg-open "$pdf"
}
# Linux-Pendant zum open-Befehl von macOS
open() { for f in "$@"; do xdg-open "$f" &>/dev/null; done; }

Beachte die Details, die du von der Seite Quoting kennst: "$1" in Anführungszeichen, $(...) für die Substitution, local für Variablen, die nur in der Funktion gelten. Das || return nach cd ist eine ShellCheck-Empfehlung: Schlägt cd fehl, bricht die Funktion ab, statt im falschen Verzeichnis weiterzumachen.

Hands-on: Definiere mkcd direkt im Terminal und probiere sie aus.

Terminal-Fenster
mkcd() { mkdir -p "$1" && cd "$1" || return; }
mkcd /tmp/neu/tief/drin
pwd
type mkcd
cd ~

type meldet, dass mkcd eine Funktion ist, und zeigt sogar ihren Code.

Der Prompt steht in PS1. Ubuntus Standard ist etwa \u@\h:\w\$ , also Benutzer, Host, Verzeichnis. Zum Ausprobieren:

Terminal-Fenster
echo "$PS1"
PS1='[\t] \w \$ '
PS1='\u@\h:\w\$ '

Die Platzhalter sind in man bash unter «PROMPTING» aufgelistet. Für die History sind drei Variablen interessant:

~/.bash_aliases
HISTSIZE=50000 # Zeilen im Speicher
HISTFILESIZE=100000 # Zeilen in ~/.bash_history
HISTCONTROL=ignoredups # gleiche Befehle nacheinander nur einmal

Dein Verzeichnis ~/bin wird von ~/.profile beim Login in den PATH aufgenommen, sofern es existiert. Möchtest du ein weiteres Verzeichnis ergänzen, gehört die Zeile ebenfalls in ~/.profile:

~/.profile
PATH="$HOME/werkzeuge:$PATH"

Schreibe $HOME, nicht ~: Innerhalb der Anführungszeichen wird die Tilde nicht ersetzt, und die Shell würde ein Verzeichnis namens ~ suchen.

Lösung anzeigen
bash_aliases
# shellcheck shell=bash
#
# Persönliche Aliase und Funktionen, wird von ~/.bashrc geladen
# Vor dem Überschreiben oder Löschen nachfragen
alias rm='rm -i'
alias cp='cp -i'
# Ausführliche Liste mit versteckten Dateien
alias ll='ls -alF'
# Ein Verzeichnis nach oben
alias ..='cd ..'
# History durchsuchen, Gross-/Kleinschreibung egal
alias hist='history | grep -i'
# Verzeichnis anlegen und hineinwechseln
mkcd() {
mkdir -p "$1" && cd "$1" || return
}
# Datei mit Datum im Namen sichern
sichern() {
local ziel
ziel="$1.$(date +%F)"
cp -v "$1" "$ziel"
}
# Längere History, Duplikate nicht doppelt speichern
HISTSIZE=50000
HISTFILESIZE=100000
HISTCONTROL=ignoredups
Terminal-Fenster
source ~/.bash_aliases
alias
type mkcd sichern
mkcd /tmp/aliastest && pwd
cp ~/.bash_aliases labs/linux/07-shell/bash_aliases
shellcheck labs/linux/07-shell/bash_aliases

Selbstcheck · 5 Fragen

1. Was bewirkt `export farbe`?
2. Warum lädt man `~/.bash_aliases` mit `source` und nicht mit `bash ~/.bash_aliases`?
3. Wann braucht es eine Funktion statt eines Alias?
4. Welche Datei liest eine neue interaktive Bash auf Ubuntu?
5. Welche Aussagen zu PATH stimmen? (mehrere Antworten möglich)