Bash-Verlauf: Die Einstellungen "Ignoriert" und "Gelöscht" widersprechen dem gemeinsamen Verlauf über mehrere Sitzungen hinweg


84

Erstens ist dies kein Duplikat eines vorhandenen Threads auf SE. Ich habe diese beiden Threads ( 1. , 2. ) über eine bessere Bash-Geschichte gelesen , aber keine der Antworten funktioniert - - ich bin übrigens auf Fedora 15.

Ich habe der .bashrcDatei im Benutzerverzeichnis (/ home / aahan /) Folgendes hinzugefügt , und es funktioniert nicht. Hat jemand eine Ahnung?

HISTCONTROL=ignoredups:erasedups  # no duplicate entries
HISTSIZE=1000                     # custom history size
HISTFILESIZE=100000                 # custom history file size
shopt -s histappend                      # append to history, don't overwrite it
PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"  # Save and reload the history after each command finishes

Okay, das ist, was ich mit der Bash-Geschichte will (Priorität):

  • Speichern Sie keine Duplikate, löschen Sie vorhandene
  • Teilen Sie die Historie sofort mit allen offenen Terminals
  • Verlauf immer anhängen, nicht überschreiben
  • Speichern von mehrzeiligen Befehlen als einzelner Befehl (standardmäßig deaktiviert)
  • Was ist die Standardgröße für Verlauf und Verlaufsdatei?

stoßen! jemand? Nichts funktioniert. Könnte dies ein Problem mit Fedora 15 sein (mit Gnome 3 und ausgeführt auf einer virtuellen Windows-Hostmaschine)?
its_me

Bitte "stoße" hier nicht an. Wenn sie nicht beantwortet werden, müssen Sie klarer nachfragen und die richtigen Kontexthinweise oder ähnliches angeben. Wenn Sie auf Ihre Posts achten müssen, können Sie Kopfgelder ausgeben, mit denen mehr Leute ihnen mehr Aufmerksamkeit schenken.
Caleb

1
Bist du sicher, dass du Bash benutzt? ( echo $SHELL). Funktionieren die Einstellungen, wenn Sie sie manuell von Ihrer offenen Shell aus ausführen? Da sie für so viele andere funktionieren, sind die Einstellungen offensichtlich richtig, und Sie implementieren sie nur falsch. Und kein Fedora15 / Gnome3 / als virtuelle Maschine hat wenig mit der eigentlichen Funktion von zu tun bash.
Caleb

@Caleb, erstmal Entschuldigung, dass ich den Beitrag stoße. Außerdem habe ich mein Bestes gegeben, um ganz klar zu sein. Nein, ich habe sie nicht in der Shell ausgestellt. Ich habe sie einfach kopiert und in die .bashrcDatei eingefügt . Ist das falsch? Können Sie diesem Beitrag eine "Antwort" mit den tatsächlichen Shell-Befehlen hinzufügen? (bitte mit meinem noob-
ity

1
Alles, was Sie in Skripten oder .bashrcARE-Shell-Befehlen schreiben . Skripte sind nur eine Reihe von Shell-Befehlen. Auch die Bearbeitung, die Sie kürzlich vorgenommen haben, um das exportBit zu entfernen, war eine schlechte Idee, die beibehalten werden sollte.
Caleb

Antworten:


119

Dies ist tatsächlich ein wirklich interessantes Verhalten und ich gebe zu, dass ich die Frage am Anfang stark unterschätzt habe. Aber zuerst die Fakten:

1. Was funktioniert

Die Funktionalität kann auf verschiedene Arten erreicht werden, obwohl jede etwas anders funktioniert. Beachten Sie, dass Sie in jedem Fall auf das Terminal drücken müssen, um die Historie auf ein anderes (aktualisiertes) Terminal "übertragen" zu lassen. EnterDort möchten Sie die Historie abrufen.

  • Option 1:

    shopt -s histappend
    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"

    Dies hat zwei Nachteile:

    1. Beim Anmelden (Öffnen eines Terminals) wird der letzte Befehl aus der Protokolldatei zweimal in den Protokollpuffer des aktuellen Terminals eingelesen.
    2. Die Puffer verschiedener Terminals bleiben nicht mit der Verlaufsdatei synchron.
  • Option 2:

    HISTCONTROL=ignoredups
    PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

    (Ja, keine Notwendigkeit shopt -s histappendund ja, es muss history -c in der Mitte sein PROMPT_COMMAND) Diese Version hat auch zwei wichtige Nachteile:

    1. Die History-Datei muss initialisiert werden. Es muss mindestens eine nicht leere Zeile enthalten (kann alles sein).
    2. Der historyBefehl kann eine falsche Ausgabe liefern - siehe unten.

[Bearbeiten] "Und der Gewinner ist ..."

  • Option 3:

    HISTCONTROL=ignoredups:erasedups
    shopt -s histappend
    PROMPT_COMMAND="history -n; history -w; history -c; history -r; $PROMPT_COMMAND"

    Das ist so weit wie es geht. Es ist die einzige Option, bei der beide erasedupsund die gemeinsame Historie gleichzeitig arbeiten. Dies ist wahrscheinlich die endgültige Lösung für alle Ihre Probleme, Aahan.


2. Warum scheint Option 2 nicht zu funktionieren (oder: was funktioniert wirklich nicht wie erwartet)?

Wie bereits erwähnt, funktioniert jede der oben genannten Lösungen anders. Aber die irreführende Interpretation, wie die Einstellungen arbeiten kommt von der Ausgabe des Analyse - historyBefehls . In vielen Fällen kann der Befehl eine falsche Ausgabe liefern . Warum? Weil es vor der Folge anderer historyBefehle ausgeführt wird, die in der PROMPT_COMMAND! Wenn Sie jedoch die zweite oder dritte Option verwenden, können Sie die Änderungen des .bash_historyInhalts überwachen ( watch -n1 "tail -n20 .bash_history"z. B. mithilfe von) und den tatsächlichen Verlauf abrufen.

3. Warum ist Option 3 so kompliziert?

Es liegt alles in der Art und Weise, wie es erasedupsfunktioniert. Da die bash Handbuch erklärt, „(...) erasedupsbewirkt , dass alle vorherigen Zeilen die aktuelle Zeile passend aus der History - Liste entfernt werden , bevor diese Zeile gespeichert wird“ . Das ist also wirklich das, was das OP wollte (und nicht nur, wie ich vorher dachte, dass keine Duplikate nacheinander auftauchen ) . Hier ist der Grund, warum jeder der history -.Befehle entweder in der folgenden Liste stehen muss oder nicht darf PROMPT_COMMAND:

  • history -n muss vorher da sein history -w, um von .bash_historyden Befehlen zu lesen, die von einem anderen Terminal gespeichert wurden,

  • history -w muss da sein, um den Verlauf zu speichern, um Duplikate abzulegen und zu löschen,

  • history -a darf nicht statt dort platziert werden history -w, da es nicht zum Löschen von Duplikaten führt,

  • history -cwird auch benötigt , um zu verhindern, dass der Verlaufspuffer nach jedem Befehl gelöscht wird.

  • und schließlich history -rwird benötigt , um den Verlaufspuffer aus einer Datei wiederherzustellen und damit den Verlauf für alle Terminalsitzungen gemeinsam zu nutzen.


2
+1 für "Die irreführendste Interpretation der Funktionsweise der Einstellungen ist jedoch die Analyse der Ausgabe des Befehls history." Ich denke, das ist der Kern des OP. Hervorragender Abzug.
Jasonwryan

2
Ich habe endlich deinen Standpunkt verstanden. Mit "Duplikaten" meinten Sie etwas anderes als mich. Ich habe mich nur auf Sequenzen mit demselben Befehl konzentriert . Meine Antwort wurde aktualisiert - siehe "Option 3". Um in Ihrem Fall zu testen, wie die Historie funktioniert, sollten Sie watch "tail -n 20 .bash_history"statt der auch die verwenden tail -f .bash_history.
Rozcietrzewiacz

2
Option 3 löschte gerade alle meine 100.000 Zeilen der Geschichte aus :( (Bash 3.2.25 (1) -Release)
Felipe Alvarez

2
history -cwird auch benötigt, weil dadurch verhindert wird, dass der Verlaufspuffer nach jedem Befehl in den Papierkorb verschoben wird. Warum tritt dieser Papierkorb auf?
Piotr Dobrogost

2
Deine Lösung 3 funktioniert eigentlich nicht. Es ist extrem fehlerhaft und hängt von der Reihenfolge ab, in der Benutzer Eingaben an verschiedenen Terminals vornehmen. Dies führt häufig zu Befehlsverlusten, insbesondere beim Hin- und Herwechseln zwischen Terminals. Quelle: ausprobiert.
6cef,

8

In Ihrem Eingabeaufforderungsbefehl verwenden Sie den -cSchalter. Von man bash:

-c   Löscht die Verlaufsliste, indem alle Einträge gelöscht werden

Um Ihren Verlauf mit allen offenen Terminals zu teilen, können Sie Folgendes verwenden -n:

-n   Liest die Verlaufszeilen, die noch nicht aus der Verlaufsdatei gelesen wurden, in die aktuelle Verlaufsliste. Dies sind Zeilen, die seit Beginn der aktuellen Bash-Sitzung an die Verlaufsdatei angehängt wurden.

Die Standardgröße finden Sie auch im Handbuch:

HISTSIZE Die Anzahl der Befehle, die im Befehlsverlauf gespeichert werden sollen (siehe HISTORY unten). Der Standardwert ist 500.

So speichern Sie mehrzeilige Befehle:

Die cmdhist Shell Option, wenn aktiviert, führt die Shell zu versuchen , jede Zeile eines mehrzeiligen Befehls in dem gleichen Geschichte Eintrag zu speichern, das Hinzufügen Semikolons erforderlichenfalls syntaktische Korrektheit zu bewahren. Die Option lithist shell bewirkt, dass die Shell den Befehl mit eingebetteten Zeilenumbrüchen anstelle von Semikolons speichert.

Außerdem sollten Sie HIST * -Befehlen keine Präfixe voranstellen export- es handelt sich um reine Bash-Variablen, nicht um Umgebungsvariablen. Dies HISTCONTROL=ignoredups:erasedupsist ausreichend.


Das export PROMPT_COMMAND="history -a; history -n; history -r; $PROMPT_COMMAND"ist also richtig? Wissen Sie auch, wie ich die Verlaufsdatei dazu bringen kann, mehrzeilige Befehle als einen einzigen Befehl zu speichern (was standardmäßig deaktiviert ist)?
its_me

1
Ja. Wie in der Manpage oben angegeben, shopt -s cmdhistwerden mehrere Zeilen gespeichert.
Jasonwryan

Okay, ich habe sie alle ausprobiert. Sieht so aus, als würde HISTCONTROL=ignoredups:erasedupses nicht funktionieren. Ich habe auch versucht, genau das in der .bashrcDatei zu haben (unter den benutzerdefinierten Funktionen). Irgendeine Idee, was falsch sein könnte? Ich verwende Fedora 15 auf einer virtuellen Maschine - - Windows 7-Host.
its_me

Vergewissern Sie sich, dass in den anderen Startdateien, wie z. B. usw., nichts vorhanden ist /etc/bashrc, .bash_profiledas diese überschreibt.
Jasonwryan

Ich sehe keine Probleme mit der .bash_profileDatei. Was den Inhalt in /etc/bashrcich es hier setzen, nehmen Sie bitte einen Blick - pastebin.com/Uae6sE6s
its_me

8

Dies ist, was ich mir ausgedacht habe und ich bin soweit zufrieden damit ...

alias hfix='history -n && history | sort -k2 -k1nr | uniq -f1 | sort -n | cut -c8- > ~/.tmp$$ && history -c && history -r ~/.tmp$$ && history -w && rm ~/.tmp$$'  
HISTCONTROL=ignorespace  
shopt -s histappend  
shopt -s extglob  
HISTSIZE=1000  
HISTFILESIZE=2000  
export HISTIGNORE="!(+(*\ *))"  
PROMPT_COMMAND="hfix; $PROMPT_COMMAND" 

ANMERKUNGEN:

  • Ja, es ist kompliziert ... aber es entfernt alle Duplikate und behält dennoch die Chronologie in jedem Terminal bei!
  • Mein HISTIGNOREignoriert alle Befehle, die keine Argumente haben. Dies kann von einigen Leuten nicht wünschenswert sein und kann weggelassen werden.

1

Verwenden Sie dies stattdessen:

HISTCONTROL=ignoreboth

0

Es funktioniert nicht, weil Sie vergessen:

 -n   read all history lines not already read from the history file
      and append them to the history list

Aber es scheint history -nnur fehlerhaft zu sein, wenn export HISTCONTROL=ignoreboth:erasedupses in Kraft ist.

Lass uns experimentieren:

$ PROMPT_COMMAND=
$ export HISTCONTROL=ignoreboth:erasedups
$ export HISTFILE=~/.bash_myhistory
$ HISTIGNORE='history:history -w'
$ history -c
$ history -w

Hier schalten wir das Löschen von Dups ein, schalten den Verlauf auf eine benutzerdefinierte Datei um und löschen den Verlauf. Nachdem alle Befehle ausgeführt wurden, haben wir eine leere Verlaufsdatei und einen Befehl im aktuellen Verlauf.

$ history
$ cat ~/.bash_myhistory
$ history
$ 1  [2019-06-17 14:57:19] cat ~/.bash_myhistory

Öffnen Sie das zweite Terminal und führen Sie auch diese sechs Befehle aus. Nachdem:

$ echo "X"
$ echo "Y"
$ history -w
$ history
  1  [2019-06-17 15:00:21] echo "X"
  2  [2019-06-17 15:00:23] echo "Y"

Jetzt hat Ihr aktueller Verlauf zwei Befehle und die Verlaufsdatei hat:

#1560772821
echo "X"
#1560772823
echo "Y"

Zurück zum ersten Terminal:

$ history -n
$ history
1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
2  [2019-06-17 15:03:12] history -n

Huh ... keiner der echoBefehle wird gelesen. Wechseln Sie erneut zum zweiten Terminal und:

$ echo "Z"
$ history -w

Die Verlaufsdatei lautet nun:

#1560772821
echo "X"
#1560772823
echo "Y"
#1560773057
echo "Z"

Wechseln Sie wieder zum ersten Terminal:

$ history -n
$ history
  1  [2019-06-17 14:57:19] cat ~/.bash_myhistory 
  2  [2019-06-17 15:03:12] history -n
echo "Z"

Sie können sehen, dass der echo "Z"Befehl mit zusammengeführt wird history -n.

Ein weiterer Fehler ist, dass Befehle aus dem Verlauf nach Befehlsnummer und nicht nach Befehlszeit gelesen werden, denke ich. Ich erwarte, dass andere echoBefehle in der Historie auftauchten


0

erasedups schneidet die führenden und nachfolgenden Leerzeichen nicht ab (wie in einigen Sprachen chomp). Das ist ein Fehler. Durch das Löschen werden auch nicht alle vorherigen Einträge gelöscht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.