Bash in Fedora
Bash ist die Standard-Shell in Fedora. Die Distribution liefert sie mit einer Reihe von Voreinstellungen aus. Dieser Artikel diskutiert die relevanten Konfigurationsdateien und geht darauf ein, wie sie den eigenen Ansprüchen angepasst werden können.
Persönlich verwende ich den Fedora Sway Spin. Ich konnte kein Repository mit den Konfigurationsdateien der Workstation finden, gehe aber in den folgenden Ausführungen davon aus, dass die Bash-Einstellungen für die beiden Varianten der Distribution im Kern die gleichen sind. Falls es wichtige Unterschiede gibt, wäre ich für Hinweise per Mail oder Mastodon dankbar!
Login-Shell und moderne Modi der Bash-Ausführung
Eine Shell dient dazu, installierte oder eingebaute Anwendungen auszuführen. Eine kommandozeilenbasierte Shell wird in einem sogenannten Terminal gestartet und über manuelle Tastatureingaben bedient.
Zusätzlich ist es für Zwecke der Systemadministration und Automatisierung möglich, Befehle zu Skripten zu kombinieren und gemeinsam aufzurufen, bei Bedarf mit parameterabhängigem Verhalten. Dabei helfen Programmierkonstrukte wie Kontrollstrukturen und Variablen.
Für gewöhnliche Zwecke sollten Shell-Skripte so geschrieben werden, dass sie sich bei ihrer Ausführung auf verschiedenen Computern auf völlig gleiche Weise verhalten. Statt Konfigurationsdateien zu laden, wird die Ausführungsumgebung im Rahmen des Skripts selbst definiert. Im Folgenden wird es nur um die interaktive Verwendung der Shell gehen.
Traditionell wurden Computer gänzlich textbasiert bedient. Dazu haben sich Benutzer ins Betriebssystem eingeloggt und im Anschluss über eine Shell Befehle ausgeführt, eventuell mit Eingaben über ein physisches Terminal. Terminals als eigenständige Anwendungen (oder gar Multiplexer wie Screen) gab es noch nicht, Anwender waren auf die eine Shell (oder Shell-Instanz) beschränkt.
Nun gab es auch damals schon Anwendungen, die das Terminal vollständig für sich beanspruchten.1 Um dennoch komfortabel Shell-Befehle ausführungen zu können, ohne die laufende Anwendung schließen zu müssen, gab es in Programmen wie ex
und vi
einen :sh
-Befehl. Um die umfassende Umgebung von diesen eingebetteten Shells abheben zu können, bezeichnete man sie bald als Login-Shell.
Auch in moderne Systemen werden Nutzer in der Regel zunächst dazu aufgefordert, sich mit ihrem Namen und Passwort anzumelden, in Fedora standardmäßig durch SDDM. Daraufhin wird jedoch keine interaktive Shell, sondern eine graphische Session mit der ausgewählten Desktopumgebung oder einem Fenster-Manager gestartet. Terminals sind heute fensterbasierte Anwendungen, Emulatoren der ausgestorbenen Hardware, die mit ihren eigenen Shell-Instanzen mehrfach gestartet werden können.
Wenn eine Shell mit einem Terminal-Emulator gestartet wird, handelt es sich für gewöhnlich nicht um eine Login-Shell im traditionellen Sinne. Um diese Rolle unter bestimmten Umständen noch immer spielen zu können, gibt es in Bash den Login-Modus. Um die Shell manuell in diesem Modus aufzurufen, kann das --login
-Flag übergeben werden.
Meinem Eindruck nach ist nicht mehr klar umgrenzt, welche Kontexte einen Login im relevanten Sinne involvieren. Aus diesem Grund ist es schwieriger zu entscheiden, welche besonderen Anforderungen an die Konfiguration dieser Umgebung zu stellen sind. Tendenziell wird der Login-Modus wohl am ehesten für Zwecke der generellen Systemadministration genutzt, und die Inhalte in Fedora spiegeln dieses intuitive Verständnis. Ein paradigmatisches Beispiel eines Login-Kontextes ist die Anmeldung in ein System über eine SSH-Verbindung.
Ähnlich wie man für einen Terminal-Emulator festlegt, welche Shell gestartet werden soll, kann man für einen Benutzer des Betriebssystems seine Login-Shell auswählen. Distributionen nutzen dazu für gewöhnlich Bash, so auch Fedora. Es ist aber natürlich möglich, eine andere Shell (wie Zsh oder Fish) einzustellen, beispielsweise mit:
sudo chsh --shell <path-to-shell> <user-name> # See /etc/shells for valid options
Die in diesem Abschnitt erläuterte Unterscheidung ist wichtig, weil im Login-Modus andere Konfigurationsdateien geladen werden als bei einer gewöhnlichen Ausführung im Terminal-Emulator. Im Folgenden wird es in erster Linie darum gehen, um welche Dateien es sich dabei handelt und in welcher Reihenfolge sie eingebunden werden.
Bash kann noch in weiteren Modi gestartet werden, etwa funktional beschränkt für Kompatibilität mit dem POSIX-Standard. Die Modi sind kombinierbar: eine Login-Shell beispielsweise wird typischerweise interaktiv bedient. Im Folgenden wird es nur um die Modi gehen, für die spezifische Konfigurationsdateien vorgesehen sind.
Welche Dateien von Bash automatisch geladen werden
Wie im vorausgegangenen Abschnitt gesagt, werden einige Konfigurationsdateien von Bash
automatisch geladen. Dabei ist zwischen den globalen und den nutzerspezifischen Shell-Einstellungen zu unterscheiden: letztere finden sich im Home-Verzeichnis, die globalen Konfigurationsdateien unter /etc/
.
Die Bash-Manpage gibt folgende Erklärung für diese Dateien:
/etc/profile
: “The systemwide initialization file, executed for login shells”~/.bash_profile
: “The personal initialization file, executed for login shells”~/.bashrc
: “The individual per-interactive-shell startup file”/etc/bash.bash_logout
: “The systemwide login shell cleanup file, executed when a login shell exits”~/.bash_logout
: “The individual login shell cleanup file, executed when a login shell exits”
Das Startverhalten kann mit --noprofile
und --norc
für die entsprechenden Dateien unterbunden werden. Dies betrifft sowohl die nutzerspezifische als auch die systemweite Konfiguration. Mit --rcfile
kann der Pfad zu einer Konfigurationsdatei übergeben werden, etwa um dem
XDG-Standard folgend das ~/.config
-Verzeichnis zu nutzen.
Für die Login-Shell gibt es eine systemweite Konfigurationsdatei, aber eine /etc/bashrc
wird in der Manpage nicht angeführt. Andere Distributionen nutzen /etc/bash.bashrc
, doch auch diese wird im Manual nicht genannt. Sie dürfte demnach nicht Teil des Standards sein (dazu sofort mehr).
In diesem Zusammenhang kann vielleicht noch erwähnt werden, dass die systemweite profile
für die Login-Shell geladen wird, auch wenn es eine lokale profile
-Konfiguration gibt. Sie dient also nicht bloß als Fallback. Außerdem ist die .bash_profile
-Bezeichnung im Nutzerverzeichnis nicht alternativlos. Möglich wären auch .bash_login
oder .profile
. Sie schließen sich wechselseitig aus: geladen wird nur die erste gefundene Datei, wobei zuerst nach bash_profile
, dann nach bash_login
und schließlich nach profile
gesucht wird.
Skripte werden von Bash nicht nur beim Start, sondern auch beim Ende einer Shell-Session ausgeführt. Wie die Manpage erklärt, dienen logout
-Dateien dazu, automatisiert einige Aufräumarbeiten vorzunehmen. Fedora überlässt es seinen Nutzern, diese Dateien für eigene Zwecke anzulegen, weshalb wir hier auch nicht auf sie eingehen werden.
In Fedora werden weitere Dateien geladen
In Fedora werden standardmäßig weitere Dateien mit Bash gesourced. Der wichtigste Unterschied besteht darin, dass zusätzlich eine systemweite /etc/bashrc
definiert und explizit zu Beginn der benutzerspezifischen .bashrc
importiert wird. So wird wie bei der Login-Shell zunächst die systemweite und im Anschluss die nutzerspezifische Konfiguration geladen.
In der Konfiguration für den Login-Modus werden die Einstellungen einer gewöhnlichen Terminal-Session geladen, indem die lokale .bashrc
in der .bash_profile
und die globale bashrc
in der /etc/profile
importiert wird. Darin liegt ein Unterschied zum Bash-Standardverhalten, bei dem die Konfiguration der Login-Shells gänzlich unabhängig vorgenommen wird.
So sind in einer Login-Shell die gleichen Aliases und Funktionen verfügbar, die dem Nutzer aus anderen Kontexten vertraut sind. Falls in den RC-Dateien zusätzlich Umgebungsvariablen gesetzt werden, wird so die Profile-Umgebung erweitert oder modifiziert.
Ein Check-Mechanismus stellt dabei sicher, dass die globale RC-Datei in einer Bash-Session nur einmal geladen wird:
# /etc/bashrc
# Prevent doublesourcing
if [ -z "$BASHRCSOURCED" ]; then
BASHRCSOURCED="Y"
Ohne diese Abfrage würde sie im Login-Kontext zuerst systemweit (in /etc/profile
) und dann lokal (in .bash_profile
) ausgeführt.
Auf weitere Konfigurationsskripte, die mit *.sh
-Endung unter /etc/profile.d/
abgelegt werden, wird in beiden Modi zugegriffen. Dazu werden sie sowohl in der /etc/profile
als auch in der /etc/bashrc
manuell importiert, anders als das Benennungsschema vielleicht nahelegt.
Dieses Verzeichnis ist auch für eigene systemweite Konfigurationen vorgesehen, etwa unter /etc/profile.d/custom.sh
. Für lokale Konfigurationsmodule einer gewöhnlichen Shell-Session dient ~/.bashrc.d/
, deren Inhalte in der ~/.bashrc
importiert werden. Dieses Verzeichnis existiert in Fedora nicht von Haus aus.
Der Verwendungszweck der Konfigurationsdateien
Wie erläutert werden je nach Ausführungsmodus verschiedene Konfigurationsdateien automatisch geladen. Fedora geht über diesen von Bash vorbestimmten Zweck hinaus und legt inhaltlich fest, welche Arten von Einstellungen in ihnen jeweils vorgenommen werden sollen.
Die Kommentare zu Beginn von /etc/profile
und /etc/bashrc
erläutern:
profile
ist für “System wide environment and startup programs, for login setup”, das heißt für die Definition von Umgebungsvariablen und von Programmen, die beim Start von Bash automatisch ausgeführt werden sollen; undbashrc
ist für “system wide functions and aliases”.
Wie der “for login setup”-Zusatz anzeigt, wird die Unterscheidung erstmal nur für den Login-Kontext unterstellt. Für eine gewöhnliche Terminal-Session wird die darin definierte Umgebung nicht ohne Weiteres berücksichtigt – ganz einfach deshalb, weil /etc/profile
in diesem Fall standardmäßig gar nicht importiert wird.
Vielleicht basiert die Unterscheidung auf dem Grundsatz, dass nur für eine Login-Shell eine systemweite Umgebung definiert werden sollte, während wir für eine gewöhnliche Terminal-Session nur auf Nutzerebene eine bestimmte Umgebung festlegen. Falls ja, so liegt mir die Begründung für dieses Prinzip nicht klar auf der Hand.
Am besten nutzt man für eigene Konfigurationen einfach ausschließlich die nutzerspezifische .bashrc
(mit bashrc.d
), insbesondere bei Systemen mit nur einem aktiven Nutzer. Wer grundsätzlich keinen Sinn in der veralteten Idee einer Login-Shell sieht, braucht die lokale .bash_profile
nicht mehr anzufassen. In ihr wird in Fedora (nur) die .bashrc
importiert, wodurch Einstellungen darin auf den Login-Kontext übertragen werden.
Die systemweiten /etc/profile
und /etc/bashrc
sollten nur in Ausnahmefällen bearbeitet werden, wie auch eine Warnung zu Beginn der Dateien vermittelt. Ihr Inhalt wird von den Fedora-Maintainers gepflegt, weshalb Änderungen mit zukünftigen Updates der Distribution verloren gehen würden.
Voreinstellungen
In den bisher angesprochenen Dateien werden einige Voreinstellungen definiert, auf die wir in diesem Abschnitt eingehen. Sie betreffen nicht nur Bash selbst, sondern auch das Verhalten bestimmter CLI-Anwendungen.
In den folgenden Unterabschnitten werden Ausschnitte als Listings eingebunden. An zwei oder drei Stellen füge ich weniger bedeutsame Anmerkungen als eigene kurze Kommentare hinzu. Die Listings sind thematisch strukturiert und entsprechen nicht dem exakten Ablauf der präsentierten Dateien.
Umgebung
Wenn ein Nutzer Bash in einem Terminal-Emulator startet, wird standardmäßig nur die ~/.bashrc
gesourced. Wir haben bereits gesehen, dass darin in Fedora weitere Konfigurationsdateien eingebunden werden:
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific aliases and functions
if [ -d ~/.bashrc.d ]; then
for rc in ~/.bashrc.d/*; do
if [ -f "$rc" ]; then
. "$rc"
fi
done
fi
unset rc
Darüber hinaus findet sich darin nur eine Definition, die zwei Verzeichnisse im Home-Verzeichnis dem Pfad hinzufügt, nämlich ~/.local/bin/
und ~/bin/
:
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]; then
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH
Wie der Kommentar-Titel anzeigt, können an dieser Stelle weiterer nutzerspezifische Umgebungsvariablen definiert werden. Ein zusätzlicher export
ist notwendig, damit sie auch in Kind-Prozessen der Shell – von ihr aufgerufene Skripte und andere Programme – zur Verfügung stehen.
Für eine Login-Shell wird eine Umgebung mit einigen System-Informationen hergestellt. Sie werden in der systemweiten profile
-Datei definiert:
if [ -x /usr/bin/id ]; then
if [ -z "$EUID" ]; then
# ksh workaround
EUID=`/usr/bin/id -u`
UID=`/usr/bin/id -ru`
fi
USER="`/usr/bin/id -un`"
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"
fi
HOSTNAME=$(/usr/bin/hostnamectl --transient 2>/dev/null) || \
HOSTNAME=$(/usr/bin/hostname 2>/dev/null) || \
HOSTNAME=$(/usr/bin/uname -n)
export PATH USER LOGNAME MAIL HOSTNAME
Der Pfad für diesen Kontext wird mit einer Hilfsfunktion definiert:
pathmunge () {
case ":${PATH}:" in
*:"$1":*)
;;
*)
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
esac
}
# Path manipulation
if [ "$EUID" = "0" ]; then
pathmunge /usr/sbin
pathmunge /usr/local/sbin
else
pathmunge /usr/local/sbin after
pathmunge /usr/sbin after
fi
unset -f pathmunge
Die sbin
-Verzeichnisse enthalten Binärdateien für Werkzeuge, die zur Systemverwaltung verwendet werden. Dazu gehören Anwendungen wie ipconfig
, fdisk
oder shutdown
, die in einem Login-Kontext schnell zur Hand sein sollten.
Interessanterweise finden sich die sbin
-Komponenten auch im Pfad einer gewöhnlichen Terminal-Session. Ich konnte keinen Eintrag in den RC-Dateien finden, der für dieses Verhalten verantwortlich ist.
Um eigene Änderungen an der globalen Umgebung der Login-Shell vorzunehmen, ist in Fedora die Datei /etc/profile.d/sh.local
vorgesehen. In einem neu aufgesetzten System enthält sie nur einen Kommentar:
#Add any required envvar overrides to this file, it is sourced from /etc/profile
An dieser Stelle könnte man Umgebungsvariablen definieren, ohne dass die Definitionen durch Updates der Distribution überschrieben werden.
Eingabeaufforderung
In einer Shell zeigen Symbole wie $
oder >
dem Nutzer an, dass eine Eingabe erwartet wird. Man bezeichnet diesen Teil der Terminalanzeige als Eingabeaufforderung oder (wie im Englischen) als Prompt.
In Bash enthält die Eingabeaufforderung standardmäßig weitere Komponenten, die dem Nutzer einige Informationen über das laufende System vermitteln, beispielsweise:
bash-5.2$
Die Anzeige lässt sich inhaltlich und visuell flexibel anpassen. In Fedora wird zunächst das Standardverhalten überschrieben:
# Change the default prompt string
[ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
Die PS1
-Umgebungsvariable wird genutzt, um mittels vordefinierter Escape-Sequenzen das Format der (primären) Eingabeaufforderung zu spezifizieren. Der erste String notiert das eben angeführte Standard-Format, bestehend aus Shell-Name (\s
), Shell-Version (\v
) und Prompt-Zeichen ($
). Die Zeile insgesamt besagt: wenn das Standard-Format verwendet wird, benutze stattdessen das Format im zweiten String. Darin steht \u
für Nutzername, \h
für Hostname und \W
für eine Kurzform vom aktuellen Arbeitsverzeichnis. Somit könnte die Anzeige so aussehen:
[kai@fedora-laptop www]$
Mit der PROMPT_COMMAND
-Umgebungsvariable kann ein Befehl gesetzt werden, der vor jeder Anzeige der Eingabeaufforderung ausgeführt wird. In Fedora wird sie folgendermaßen definiert:
# are we an interactive shell?
if [ "$PS1" ]; then
if [ -z "$PROMPT_COMMAND" ]; then
declare -a PROMPT_COMMAND
case $TERM in
xterm*)
if [ -e /etc/sysconfig/bash-prompt-xterm ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-xterm
else
PROMPT_COMMAND='printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"'
fi
;;
screen*)
if [ -e /etc/sysconfig/bash-prompt-screen ]; then
PROMPT_COMMAND=/etc/sysconfig/bash-prompt-screen
else
PROMPT_COMMAND='printf "\033k%s@%s:%s\033\\" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/\~}"'
fi
;;
*)
[ -e /etc/sysconfig/bash-prompt-default ] && PROMPT_COMMAND=/etc/sysconfig/bash-prompt-default
;;
esac
fi
fi
Einem Standard folgend, werden Skripte unter /etc/sysconfig/
als Prompt-Befehl ausgeführt, sollten sie vorhanden sein. Hier wird zwischen einem gewöhnlichen Terminal (der Wert von $TERM
beginnt mit xterm*
) und einem
Terminal-Multiplexer (der Wert von $TERM
beginnt mit screen*
) unterschieden.
Die beiden Dateien existieren in Fedora nicht standardmäßig. Stattdessen wird ein printf
-Befehl mit unsichtbarer Ausgabe genutzt, um den Titel des Terminal-Fensters festzulegen. Ändert sich die vordergründig ausgeführte Anwendung, so ändert sich dynamisch mit jedem Aufruf auch der Fenster-Titel. Der Befehl könnte auch genutzt werden, um sichtbar Informationen in der Zeile über der Eingabeaufforderung anzuzeigen. Die Variable kann auf Nutzer-Ebene überschrieben werden, wie etwa bei Verwendung vom
Starship-Prompt.
Unter /etc/profile.d/bash-color-prompt.sh
findet sich ein Skript, mit dessen Hilfe Komponenten der Eingabeaufforderung farbig hervorgehoben werden können. Eine Erklärung seiner Verwendung findet sich unter /usr/share/doc/bash-color-prompt/README.md
.
Internationalisierung
Einige CLI-Anwendungen richten sich für ihre Internationalisierung (i18n) nach den Werten bestimmter Umgebungsvariablen. Das ist beispielsweise für
GNU AWK der Fall. Fedora nutzt /etc/profile.d/lang.sh
, um durch sinnvolle Fallbacks eine ordnungsgemäße Funktionsweise zu gewährleisten.
Mit dem locale
-Befehl lässt sich abfragen, ob die LC_*
-Umgebungsvariablen sachgerecht definiert wurden (für ihren intendierten Zweck siehe beispielsweise das
Arch-Wiki). Probleme bei der Lokalisierung drohen, wenn der Befehl Fehler ausgibt. In diesem Fall werden die Variablen in der lang.sh
auf ihre Standardwerte zurückgesetzt:
# If unavailable, reset to the default. Do this before reading in any
# explicit user configuration. We simply check if locale emits any
# warnings, and assume that the settings are invalid if it does.
if [ -n "$(/usr/bin/locale 2>&1 1>/dev/null)" ]; then
[ -z "$LANG" ] || LANG=C.UTF-8
unset LC_ALL # Falls sie definiert wäre, würden die anderen Werte überschrieben
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_PAPER="C.UTF-8"
LC_NAME="C.UTF-8"
LC_ADDRESS="C.UTF-8"
LC_TELEPHONE="C.UTF-8"
LC_MEASUREMENT="C.UTF-8"
LC_IDENTIFICATION="C.UTF-8"
fi
Als nächstes wird die Umgebung hergestellt, wie sie in zwei Standard-Konfigurationsdateien definiert wird: /etc/locale.conf
und ~/.i18n
. Die letztgenannte Datei existiert in Fedora nicht von Haus aus, erstgenannte enthält nur eine einzige Variablendefinition. Ihr Wert hängt davon ab, was während der Fedora-Installation eingestellt wurde, beispielsweise:
LANG="en_US.UTF-8"
Der Import dieser Einstellungen in der lang.sh
enthält einen Sicherheitsmechanismus:
for config in /etc/locale.conf "${HOME}/.i18n"; do
if [ -f "${config}" ]; then
# NOTE: We are using eval & sed here to avoid invoking of any commands & functions from those files.
if [ -x /usr/bin/sed ]; then
eval $(/usr/bin/sed -r -e 's/^[[:blank:]]*([[:upper:]_]+)=([[:print:][:digit:]\._-]+|"[[:print:][:digit:]\._-]+")/export \1=\2/;t;d' ${config})
else
#but if we don't have sed, let's go old way and source it
[ -f "${config}" ] && . "${config}"
fi
fi
done
So wird sichergestellt, dass nur Zeilen im Variable=Wert
-Format importiert werden. Diese Verarbeitungsweise verhindert, dass Bash unbeabsichtigt (andere) Befehle ausführt. Zur Verarbeitung wird sed
vorausgesetzt; sollte diese Standardanwendung wider Erwarten nicht verfügbar sein, so würde der Inhalt auf direkte Weise auf einen Schlag gesourced.
Ein weiterer Sicherheitsmechanismus in der lang.sh
betrifft die LC_ALL
-Umgebungsvariable. Da sie alle anderen LC_*
-Werte überschreiben würde, sollte sie nur mit bedacht und explizit gesetzt werden. Das wird mit der folgenden Konfiguration sichergesetellt:
# The LC_ALL is not supposed to be set in /etc/locale.conf according to 'man 5 locale.conf'.
# If it is set, then we we expect it is user's explicit override (most likely from ~/.i18n file).
# See 'man 7 locale' for more info about LC_ALL.
if [ -n "${LC_ALL}" ]; then
if [ "${LC_ALL}" != "${LANG}" -a -n "${LANG}" ]; then
export LC_ALL
else
unset LC_ALL
fi
fi
Ein letzter Sicherheitsmechanismus betrifft sogenannte
virtuelle Konsolen (die Erben der echten Login-Shell). Sie werden mit dem Betriebssystem gestartet und wir können sie mit Strg+Alt+F<1-9>
betreten. Insbesondere sind sie auch in einem modernen System nicht graphischer Natur, was zu Problemen bei Sprachen führen kann, die gewisse Sonderzeichen verwenden. Dazu zählen beispielsweise Japanisch, Koreanisch oder Arabisch.
# The ${LANG} manipulation is necessary only in virtual terminal (a.k.a. console - /dev/tty*):
if [ -n "${LANG}" ] && [ "${TERM}" = 'linux' ] && /usr/bin/tty | /usr/bin/grep --quiet -e '/dev/tty'; then
if /usr/bin/grep --quiet -E -i -e '^.+\.utf-?8$' <<< "${LANG}"; then
case ${LANG} in
ja*) LANG=en_US.UTF-8 ;;
ko*) LANG=en_US.UTF-8 ;;
si*) LANG=en_US.UTF-8 ;;
zh*) LANG=en_US.UTF-8 ;;
ar*) LANG=en_US.UTF-8 ;;
fa*) LANG=en_US.UTF-8 ;;
he*) LANG=en_US.UTF-8 ;;
en_IN*) true ;;
*_IN*) LANG=en_US.UTF-8 ;;
esac
else
case ${LANG} in
ja*) LANG=en_US ;;
ko*) LANG=en_US ;;
si*) LANG=en_US ;;
zh*) LANG=en_US ;;
ar*) LANG=en_US ;;
fa*) LANG=en_US ;;
he*) LANG=en_US ;;
en_IN*) true ;;
*_IN*) LANG=en_US ;;
esac
fi
# NOTE: We are not exporting the ${LANG} here again on purpose.
# If user starts GUI session from console manually, then
# the previously set LANG should be okay to use.
fi
Für eine virtuelle Konsole werden die Einstellungen zur Sprache in diesen Fällen durch Englisch überschrieben.
Bash-Optionen
Bash selbst kann über Umgebungsvariablen und über einige Optionen konfiguriert werden, die sich mit dem eingebauten shopt -s
-Befehl setzen lassen. Die verfügbaren Optionen und ihre eingstellten Werte kann man sich anzeigen lassen, indem man shopt
ohne Argumente ausführt.
Sicher kann man darüber streiten, welche Optionen als sinnvolle Defaults gesetzt werden sollten. Fedora bleibt hier weitestgehend neutral und aktiviert nur zwei solche Optionen:
# /etc/bashrc
# Turn on parallel history
shopt -s histappend
# Turn on checkwinsize
shopt -s checkwinsize
checkwinsize
sorgt dafür, dass sich Bash-Inhalte dynamisch den neuen Bedingungen anpassen, wenn die Größe des Terminal-Fensters geändert wird. histappend
betrifft den Fall, dass mehrere Bash-Sessions zugleich gestartet werden. Ohne Weiteres verhält sich die Shell so, dass jede neue gestartete Session die History-Datei (~/.bash_history
) überschreibt. Es würde somit immer nur von der letzten Session abhängen, welche zuletzt ausgeführten Befehle in den Verlauf aufgenommen werden. Die angeführte Option bewirkt, dass die verschiedenen Sessions ihre Befehle parallel der History-Datei anhängen (append).
Das systemweite Profil umfasst zwei weitere Einstellungen, die die Bash-History betreffen:
# /etc/profile
if [ -z "$HISTSIZE" ] ; then
HISTSIZE=1000 # maximum number of commands stored
fi
if [ "$HISTCONTROL" = "ignorespace" ] ; then
export HISTCONTROL=ignoreboth
else
export HISTCONTROL=ignoredups
fi
export HISTSIZE HISTCONTROL
Die Abfrage betrifft ignorespace
und ignoredups
. Letztgenannte Option bereinigt die History von Duplikaten: Wenn sich ein eben ausgeführter Befehl bereits in der History befindet, wird er am Ende angehängt und der frühere Eintrag entfernt. Die ignorespace
-Option gibt Nutzern eine einfache Möglichkeit, einen Befehl auszuführen, ohne ihn der History hinzuzufügen (indem ein Leerzeichen vorangestellt wird).
Beide Zweige der Abfrage besagen, dass die History einer Login-Shell keine Duplikate enthalten soll. Im zweiten Fall völlig explit und im ersten Fall dadurch, dass die ignoreboth
-Option ignorespace
und ignoredups
umfasst.
Viele Anwender werden checkwinsize
und ignoredups
wohl auch in ihrer nutzerspezifischen Konfiguration setzen wollen. Einige weitere Einstellungen sind empfehlenswert:
shopt -s cmdhist # Store multi-line commands as single history entry
shopt -s xpg_echo # Allow escape sequences like `\n` in `echo` (POSIX standard)
shopt -s nullglob # Unmatched globbing patterns expand to nothing (instead of pattern)
shopt -s nocaseglob # Case-insensitive globbing
shopt -s autocd # Change directory without prepended `cd`
shopt -s cdspell # Fix minor typos in `cd` commands
Aliases
Gängige Shell-Befehle wie grep
und ls
werden in Fedora standardmäßig farblich dargestellt. Ihre jeweilige Manpage zeigt, dass dazu Flags gesetzt werden können. Interessanterweise wird ihre Ausgabe auch dann in Farbe angezeigt, wenn die genannten Flags explizit gar nicht verwendet werden. Außerdem stehen zusätzliche Befehle wie ll
für eine ls
-Listenansicht zur Verfügung.
Der Grund für diese Verhaltensweisen liegt darin, dass einige Aliases vorhandene Befehle umdeuten. Wir können sie uns auf folgende Weise auflisten lassen:
> alias
alias egrep='grep -E --color=auto'
alias fgrep='grep -F --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias which='(alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot'
alias xzegrep='xzegrep --color=auto'
alias xzfgrep='xzfgrep --color=auto'
alias xzgrep='xzgrep --color=auto'
alias zegrep='zegrep --color=auto'
alias zfgrep='zfgrep --color=auto'
alias zgrep='zgrep --color=auto'
Die ausgegebenen Definitionen finden sich (vielleicht etwas versteckt) in Modulen unter /etc/profile.d/
. Beispielsweise erscheint grep
aufgrund folgender Einstellung farbig:
# /etc/profile.d/colorgrep.sh
/usr/libexec/grepconf.sh -c || return
alias grep='grep --color=auto' 2>/dev/null
alias egrep='grep -E --color=auto' 2>/dev/null
alias fgrep='grep -F --color=auto' 2>/dev/null
Aufgrund dieser Definitionen sind auch die zusätzlichen Befehle egrep
und fgrep
verfügbar. Völlig analog verhält es sich mit zgrep
, xzgrep
und ls
. colorls.sh
enthält darüber hinaus Definitionen für die zusätzlichen Befehle ll
und l.
.
Es gibt weitere Standard-Tools mit Farb-Option. Beispielsweise könnte man die folgende Datei hinzufügen:
# /etc/profile.d/colorip.sh
alias ip='ip -color=auto'
Der which
-Befehl wird durch ein Alias um eine hilfreiche Funktion erweitert (je nach verwendeter Shell):
# Initialization script for bash, sh, mksh and ksh
case "$(basename $(readlink /proc/$$/exe))" in
*ksh*|zsh)
alias which='alias | /usr/bin/which --tty-only --read-alias --show-tilde --show-dot'
;;
bash|sh)
alias which='(alias; declare -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot'
;;
*)
;;
esac
Für gewöhnlich erkennt which
nur Binärdateien auf dem Pfad. Durch diese Neudefinition wird vorab geprüft, ob ein Alias mit dem in Frage stehenden Namen existiert. Aus diesem Grund wird durch which ll
beispielsweise die entsprechende Alias-Definition angezeigt; der gewöhnliche which
-Befehl hätte lediglich darauf hinwiesen, dass sich ll
nicht auf dem Pfad befindet.
Konfiguration einiger CLI-Anwendungen
In Fedora finden sich unter /etc/profile.d/
einige anwendungsspezifische Skripte. So wird in der gawk.sh
festgelegt, welche Bibliotheken in AWK zur Verfügung stehen, ohne dass der vollständige Pfad eingegeben werden muss.
GAWKPATH und
GAWKLIBPATH fungieren dabei sehr ähnliche wie die PATH
-Umgebungsvariable der Shell.
less.sh
ist dafür verantwortlich, dass less
nicht nur Textdateien, sondern auch Binärdateien einiger bestimmter Typen “öffnen” kann.
# less initialization script (sh)
if [ -z "$LESSOPEN" ] && [ -x /usr/bin/lesspipe.sh ]; then
# The '||' here is intentional, see rhbz#1254837.
export LESSOPEN="||/usr/bin/lesspipe.sh %s"
fi
Mit LESSOPEN
wird ein Befehl definiert, der jedem less
-Aufruf vorausgehend ausgeführt wird. Der verwendete lesspipe.sh
-Filter legt fest, was je nach Dateityp passieren soll. Das Skript sorgt unter anderem dafür, dass man sich mit less
den Inhalt von Archiven und Bildinformationen anzeigen lassen kann.
Die anwendungsbezogenen Skripte können sehr einfach sein. nano-default-editor.sh
ist dafür verantwortlich, dass Nano als Wert für EDITOR
gesetzt wird (falls die Variable nicht bereits definiert oder später überschrieben wurde). Diese Einstellung hätte man sicher auch weniger verschachtelt vornehmen können.
gnupg2.sh
ist ein weiterer Einzeiler, dessen Effekt aber weniger offensichtlich ist:
export GPG_TTY=$(tty)
Der tty
-Befehl gibt den Pfad zum Terminal zurück, mit dem die Standardausgabe gegenwärtig verbunden ist. Die GPG_TTY
-Variable legt fest, welche TTY von
pinentry verwendet werden soll, wenn Passphrasen vom Nutzer abgefragt werden. Das verhindert Fehlermeldungen, die in gewissen Umgebungen (wie bei SSH- oder TMUX-Sessions) auftreten können.
debuginfod.sh
schließlich ist ein Skript, das Einstellungen für den gleichnamigen Dienst vornimmt. Ich werde hier nicht so tun als würde ich verstehen, was darin vor sich geht.
Autovervollständigung
Bash wird von Fedora mit der Möglichkeit ausgeliefert, Eingaben per Tastendruck zu vervollständigen (für gewöhnlich mittels der Tab-Taste). Es überrascht vielleicht, dass die Autovervollständigung nicht zu den eingebauten features der Shell gehört.
Die komplexe Funktionalität wird in /usr/share/bash-completion/bash_completion
implementiert und in /etc/profile.d/bash_completion.sh
geladen. Vervollständigungen für mehr als eintausend Anwendungen finden sich unter /usr/share/completions/
.
Diesem Verzeichnis können neue Einträge hinzugefügt werden, gerade bei neueren oder weniger verbreiteten Anwendungen. Der
Yazi-Download beispielsweise umfasst solche Dateien für seine beiden Komponenten (yazi
und ya
). An ihrer Dateiendung erkennt man, für welche Shell sie bestimmt sind.