~/.bash_history
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”
- Erneute Ausführung von Kommandos
- Was landet in der History?
- Wie vermeide ich die Speicherung in der History?
- Anzahl der Einträge
- .bash_history ergänzen, nicht überschreiben
- History über alle Shells hinweg
- histreedit
- histverify
- Formatierung
- Löschen von Einträgen
- Abschließend
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
historygenau, dass du ein bestimmtes Kommando – zum Beispieltail /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,dateoder auchhistoryselbst beispielsweise bieten üblicherweise keinen großen Mehrwert. Was „uninteressant“ ist, ist natürlich geschmacks- und umgebungsabhängig. -
Mehrfach ausgeführte: in der Standardkonfiguration kann
historyeine 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, alsoignorespaceundignoredups, 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_historyangehängt, - die History im Arbeitsspeicher komplett gelöscht und
- die Inhalte von
~/.bash_historywieder 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? 😎
8 Kommentare
Von: Antje
2025-11-11 12:05
Vielen Dank! Es ist immer wieder erschreckend, wie viele Features der bash ich nur in ihrer Grundform kenne.
Und der englischen Sprache fehlt immer noch ein einfaches Wort für das deutsche "doch", um "alias please=…" eindeutiger zu benennen.
Von: Alexander
2025-11-11 14:32
Das ist ein richtig guter Artikel, vielen Dank! Ich habe sehr viel gelernt, obwohl ich seit Jahrzehnten mit der history arbeite
Rein methodisch: Die Ersetzung mit ":1", ":2" kommt etwas überraschend zwischendurch. Vielleicht magst Du diese Funktionalität noch etwas expliziter einführen?
Und das sehr praktische "!!" für den letzten Befehl habe ich etwas vermisst ("fc" hingegen kannte ich noch nicht).
Von: Björn Starkimarm
2025-11-12 07:14
Tippfehler? Du hast im Beispiel zuerst example_short.md und dann example_short.txt
Von: sumpfsuppe
2025-11-12 09:46
Cooler Artikel, hab viel dazugelernt.
Eine Ergänzung: Anstatt einen `please`-Alias anzulegen (was ich aber schon ganz charmant finde 😁), kann man einfach `sudo !!` eintippen; das führt ebenfalls den vorherigen Befehl aus, nur eben mit vorangestelltem sudo. Hat den Vorteil, dass es auch auf fremden Installationen funktioniert.
Von: f4m8
2025-11-13 12:26
Moin,
vielen Dank für diesen Artikel. Alleine schon für das "fc" bzw das "please" shell alias hat es gelohnt. Ich habe mehr als einen "Aha, das geht also auch" Effekt beim lesen gehabt. Ja auch nach 25 Jahren bash lerne ich immer noch was hinzu. Der "good enough" Effekt verhindert das weitere forschen in der Tiefe und schützt und dafür (unötige?) Zeit zu verbrennen.
Gruß
Frank
Von: Marianne
2025-11-13 15:49
Vielen Dank für den Hinweis in Sachen Tippfehler - den habe ich soeben korrigiert! ✌️
Und ja, ich hätte noch sehr viel mehr Dinge erwähnen können, das ist ja leider immer so.
Bei "!!" bin ich tatsächlich stumpf davon ausgegangen, dass das _jeder_ kennt. Den Alias mit "please" habe ich aufgenommen, weil "alias please='sudo !!'" eben _nicht_ so ohne weiteres funktioniert. Und es ist auch mitnichten so, dass "sudo !!" *einfach so* auf Fremdsystemen funktionieren würde - ohne "sudo"-Rechte kommt man da auch nicht weit 😎
Ich hab mich dagegen entschieden, den ohnehin schon ziemlich umfangreichen Artikel noch weiter aufzublasen. Wer weiß, vielleicht schreibe ich ja irgendwann eine Fortsetzung... 🌻
Von: andreas
2025-11-29 11:14
Danke!
Von: Andread
2025-12-04 07:08
Das war doch mal sehr interessante Lektüre zum Frühstück. Vielen lieben Dank. ''please'' und ein paar Optionen werde ich direkt übernehmen 🙂
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.