~/.bash_history

Geschätzte Lesezeit: 6 Minuten

Diesen Artikel schenke ich Antje B. und Rainer R.: schon vor Wochen hatten wir uns über dieses Thema unterhalten, und die beiden ermunterten mich, etwas zum Thema zu veröffentlichen. „Klar, kein Problem“ behauptete ich großartig – und fiel dann über der Recherche wie so oft in das Dokumentations-Rabbit-Hole 😂 Der Artikel ist nun sehr viel länger… Als ursprünglich gedacht… Und auch sehr viel später… Aber nunja… 😇

Das Kommando “history”

Tippst du in der Shell das Kommando history ein, so gibt es gemäß Konfiguration die in der Vergangenheit abgesetzten Kommandos aus, sortiert vom ältesten hin zum neuesten Eintrag. Das ist insbesondere deshalb praktisch, als dass die History es ermöglicht, diese Kommandos wieder hervorzuholen und, gegebenenfalls auch modifiziert, erneut auszuführen. So muss man (vor allem längere, kompliziertere oder fehleranfällige Kommandos) nicht immer wieder vollständig eintippen. Durch die History kann die Arbeit also durchaus effizienter gestaltet werden.

1  pwd                                                    # Ältestes Kommando
2  ls                                                     # Langweilig
3  tail /var/log/syslog                                   # Kann man ja immer mal brauchen
4  ls                                                     # Duplikat von (2). Und langweilig.
5  date                                                   # Auch langweilig 🥱
7  mysql -uroot -p6pTwnpXO mysql -e "describe time_zone;" # root-Zugang zur Datenbank 💣
8  history                                                # Zuletzt ausgeführtes Kommando

Erneute Ausführung von Kommandos

Du weißt nun also, was das Kommando history tut – doch wozu ist das Ganze eigentlich gut? Nun – die History dient in erster Linie dazu, die Arbeit zu beschleunigen. Du kannst bereits getätigte Aufrufe wieder aus der History aufrufen und erneut ausführen, ohne sie erneut eintippen zu müssen, was vor allem bei wiederkehrenden Aufrufen eine enorme Zeitersparnis bedeutet. Um das zu bewerkstelligen, stehen dir mehrere Möglichkeiten offen:

  • Du kannst mit den Pfeiltasten [↑] und [↓] durch die History navigieren; erreichst du das gewünschte Kommando, führst du es – nachdem du es gegebenenfalls angepasst hast – durch Drücken von [Enter] erneut aus. Gerade bei einer umfangreichen History und weiter in der Vergangenheit liegenden Aufrufen ist die Navigation über Pfeiltasten jedoch kaum praktikabel – und es ist auch sehr schmerzhaft, anderen zusehen zu müssen, wenn sie das tun. Das stellt dann auch eher keinen Zeitgewinn mehr dar.
  • Drückst du jedoch [Ctrl+R], erscheint der Prompt (reverse-i-search)`':, und du kannst in deinen bisher getätigten Aufrufen suchen. Auch hier führst du einen Aufruf – nachdem du ihn gegebenenfalls nach Wunsch modifiziert hast – durch das Drücken von [Enter] aus.
  • Weißt du anhand der Ausgabe von history genau, dass du ein bestimmtes Kommando – zum Beispiel tail /var/log/syslog, das war im obenstehenden Beispiel Kommando #3 – ganz genau so erneut ausführen möchtest, so genügt es in unserem Beispiel, !3, also die Nummer des Aufrufs mit vorangestelltem Ausrufezeichen, in der Shell aufzurufen.
  • Eine Alternative ist das Kommando fc; das steht sowohl für „fix command“ als auch für „find command“, es kann beides. Ein Blick in die Manpage gibt dir vielleicht ein paar Ideen für Einsatzmöglichkeiten.
$ alias please='sudo $( fc -ln -1 )'    # Führt das zuletzt getätigte Kommando erneut aus, aber nun mit vorangestelltem 'sudo'

$ dmesg
dmesg: read kernel buffer failed: Operation not permitted

$ please
[    0.497142] hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0
[    0.497142] hpet0: 3 comparators, 32-bit 14.318180 MHz counter
[    0.499053] clocksource: Switched to clocksource tsc-early
[...]

Was landet in der History?

In der Grundkonfiguration wird üblicherweise jegliches Kommando aufgezeichnet, die genaue Konfiguration ist aber auch distributionsabhängig. Damit beinhaltet die History auch Kommandos wie die folgenden:

  • Total uninteressante: Aufrufe von ls, date oder auch history selbst beispielsweise bieten üblicherweise keinen großen Mehrwert. Was „uninteressant“ ist, ist natürlich geschmacks- und umgebungsabhängig.
  • Mehrfach ausgeführte: in der Standardkonfiguration kann history eine beliebige Menge an identischen Kommandos beinhalten, ohne das dies einen Mehrwert bieten würde.
  • Solche mit Passwörtern: übergibst du Passwörter auf der Kommandozeile, landen auch diese in der History – was je nach Kontext sicherheitskritisch kann.

Dem Umgang mit diesen Aspekten widmen wir uns nun.

Wie vermeide ich die Speicherung in der History?

Über die Variablen HISTCONTROL und HISTIGNORE kannst du steuern, was nicht in der History landen soll. Das ist natürlich sehr abhängig von persönlichen Präferenzen, aber halt auch vom jeweiligen Kontext. Deshalb sind die nachfolgenden Angaben auch eher als Einladung zur Weiterentwicklung zu verstehen, nicht als „einzige Wahrheit“.

Für HISTCONTROL gibt es die folgenden möglichen Werte:

  • ignorespace: Kommandos, denen ein Leerzeichen vorangestellt wird, landen nicht in der History; nützlich beispielsweise, wenn doch einmal ein Passwort übergeben werden soll
  • ignoredups: stimmt eine Eingabe mit der vorherigen überein, so wird sie nur einmal in der History gespeichert
  • ignoreboth: fasst die beiden anderen, also ignorespace und ignoredups, in einem Begriff zusammen
  • erasedups: verhindert das Auftreten von Duplikaten, aber über die gesamte History hinweg (und nicht nur auf das vorangegangene Kommando bezogen)

Gemäß dieser Möglichkeiten kannst du dir nun eine HISTCONTROL nach deinen Wünschen gestalten.

## file: "~/.bashrc"
export HISTCONTROL=ignoreboth:erasedups

Über HISTIGNORE legst du dann noch fest, welche Kommandos du generell nicht in der History sehen möchtest.

## file: "~/.bashrc"
export HISTIGNORE="clear:ls:history:[bf]g:exit:date:* --help"

Anzahl der Einträge

Über die Zeit kommt da natürlich einiges an Kommandos zusammen. Deshalb gibt es zwei Umgebungsvariablen, die die Anzahl der gespeicherten Kommandos limitieren; und übersteigt die Zahl der Einträge den definierten Wert, wird der jeweils älteste Eintrag gelöscht.

So limitiert HISTSIZE die Anzahl der Elemente, die im Arbeitsspeicher vorgehalten werden; der Default sind 500. Setzt du den Wert auf 0, wird überhaupt nichts mehr in der History gespeichert, wohingegen ein Wert kleiner Null bedeutet, dass alles ohne Limit vorgehalten wird.

HISTFILESIZE ist per Default identisch dem Wert von HISTSIZE. Ein (positiver) Wert definiert, wie viele Einträge dauerhaft gespeichert, also beim nächsten Login auch wieder verfügbar sein werden. Auch für HISTFILESIZE bedeutet der Wert 0, dass überhaupt nichts mehr gespeichert wird, wohingegen ein Wert kleiner Null bedeutet, dass alles ohne Limit vorgehalten wird. Sei also aufmerksam beim Setzen dieser Variablen. Insbesondere ein zu kleiner Wert für HISTFILESIZE könnte sonst beim nächsten Login für Überraschungen sorgen.

## file: "~/.bashrc"
export HISTSIZE=2000
export HISTFILESIZE=5000

Üblicherweise geschieht diese dauerhafte Speicherung beim Verlassen der Shell in Form der Datei ~/.bash_history. Diesen Speicherort kannst du über die Variable HISTFILE nach eigenen Wünschen konfigurieren. Der Einfachheit halber referenziere ich im weiteren Verlauf aber ~/.bash_history.

.bash_history ergänzen, nicht überschreiben

Üblicherweise wird die ~/.bash_history beim Beenden einer Session schlicht überschrieben. Möchtest du das nicht, ist die Shell-Option histappend für dich: sie sorgt dafür, dass die .bash_history beim Schließen einer Session nicht stumpf überschrieben wird, sondern die aktuellen Einträge an die existierende .bash_history angefügt werden – gemäß der per HISTSIZE und HISTFILESIZE gesetzten Werte, versteht sich.

## file: "~/.bashrc"
shopt -s histappend

History über alle Shells hinweg

Jede offene Session hält ihre History in einem eigenen Speicherbereich. Das bedeutet, dass ein Kommando, das ich in Session A absetze, in der History von Session B nicht verfügbar sein wird. Und während die einen genau diesen Umstand sehr schätzen, möchten die anderen genau das anders haben.

Solltest du der zweiten Gruppe angehören, musst du im ersten Schritt sicherstellen, dass die History über histappend ergänzt (statt überschrieben) wird (s.o.). Und im zweiten Schritt musst du nun dafür sorgen, dass das zuletzt getätigte Kommando sofort in der ~/.bash_history hinterlegt und mithin allen Sessions zugänglich gemacht wird. Dies erreichst du, indem du, noch bevor ein Prompt angezeigt wird, dafür sorgst, dass

  • das zuletzt ausgeführte Kommando an ~/.bash_history angehängt,
  • die History im Arbeitsspeicher komplett gelöscht und
  • die Inhalte von ~/.bash_history wieder in die Arbeitsspeicher-History eingelesen werden.
## file: "~/.bashrc"
PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND$'\n'}history -a; history -c; history -r"

histreedit

Das Ding mit den Kommandos, die Ersetzungen enthalten, ist, dass diese nicht in der History gespeichert werden: vertippst du dich, erhältst du eine Fehlermeldung, und dann musst du das korrigierte Kommando erneut vollständig eintippen.

$ echo !8090:2
bash: :2: bad word specifier
$

Um die Arbeit an der Stelle etwas effizienter zu gestalten, gibt es die Shell-Option histreedit: diese erlaubt es, das Kommando zu korrigieren und dann erneut auszuführen.

$ echo !8090:2
bash: :2: bad word specifier
$ echo !8090:2                  # <= Editieren und mit [Enter] erneut ausführen

Über shopt | grep hist kannst du sehen, welche Optionen gerade im Sinne der History „scharfgeschaltet“ sind; und ebenfalls über shopt -s schaltest du sie ein (bzw. mit shopt -u aus).

## file: "~/.bashrc"
shopt -s histreedit

histverify

Fehler passieren, man kann sie gar nicht ausschließen. Gehen wir hier mal davon aus, die History enthält den folgenden Eintrag:

history
...
227  cat example_short.md example_long.md
...

Jetzt kommst du zu dem Schluss: example_long.md brauchst du nicht mehr, die möchtest du löschen. Und da du natürlich möglichst wenig tippen willst, machst du das auf dem folgenden Weg:

$ rm !227:1
rm example_short.md

Das Kommando wird nach Betätigen von [Enter] sofort ausgeführt, und: ARGH! Jetzt siehst du es auch: du hast 1 statt 2 angegeben und somit versehentlich example_short.md gelöscht – was jedoch überhaupt nicht in deinem Sinne war! Um das in Zukunft zu verhindern, kannst du histverify setzen: es fügt insofern eine Schwelle ein, als dass nun das Kommando nicht mehr sofort ausgeführt wird.

## file: "~/.bashrc"
shopt -s histverify

Vielmehr kannst du schauen, ob die Ersetzungen in deinem Sinne sind – und den Aufruf dann mit [Enter] ausführen.

$ rm !227:1
$ rm example_short.md    # <= Prüfen – und mit [Enter] bestätigen, wenn es so korrekt ist
$

Formatierung

Vielleicht ist es in deinem Umfeld auch wichtig, wann ein Kommando ausgeführt wurde? Nutze die Variable HISTTIMEFORMAT.

## file: "~/.bashrc"
export HISTTIMEFORMAT='%F %T - '

Die nutzt die üblichen Platzhalter, wie man sie vom Kommando date her auch kennt: so lässt sich die Ausgabe leicht um beispielsweise Datum und Uhrzeit ergänzen.

1  2025-10-30 09:48:24 - pwd
2  2025-10-30 09:59:44 - ls
3  2025-10-30 10:05:35 - tail /var/log/syslog

Löschen von Einträgen

Manchmal möchtest du vielleicht die gesamte History verwerfen.

history -c

In manchen Situationen möchtest du hingegen nur ein einzelnes Kommando löschen – im Beispiel vielleicht #7, das mit dem Datenbankpasswort.

history -d 7

Bleibt anzumerken, dass auch diese Löschkommandos wiederum in der History landen, was gegebenenfalls Rückfragen nach sich ziehen kann. Und es ist auch nicht in jeder Umgebung gewünscht beziehungsweise erlaubt, die volle History zu verwerfen – im Zweifel lieber vorher klären.

Abschließend

*tieflufthol* Das ist dann alles irgendwie wortgewaltiger geworden, als ich ursprünglich gedacht hatte. Aber immerhin: ich hab auch selbst so einiges dabei gelernt – auch wenn es mir ein bisschen peinlich ist, das überhaupt zuzugeben. Ursprünglich dachte ich nämlich, ich wüsste da alles, was relevant ist, aber: man lernt nie aus.

Und ihr so? 😎

Hintergrundbild © Marianne Spiller · Alle Rechte vorbehalten

8 Kommentare

Hinterlasse einen Kommentar

Ich freue mich über jeden Kommentar, es sei denn, er ist blöd.
Deshalb sind die Kommentare auf dieser Seite auch generell moderiert.

(Nick)Name: (erforderlich)
E-Mail: (erforderlich, wird nicht veröffentlicht)
Website: (optional)