So entfernen Sie den letzten Befehl (oder den aktuellen Befehl für den Bonus) aus dem zsh-Verlauf

12

Sicher, es gibt eine supereinfache intelligente Möglichkeit, dies zu tun, aber da der Verlauf in zshell auf fc ausgerichtet zu sein scheint, gibt es keine Möglichkeit, die unter Wie entferne ich eine einzelne Zeile aus dem Verlauf? .

Irgendwelche Hinweise, wie das geht? Mein Anwendungsfall wäre, den zuletzt ausgegebenen Befehl aus dem Verlauf zu entfernen, damit die automatische Vervollständigung beendet wird (meistens, wenn Sie etwas falsch eingegeben haben und er immer wieder angezeigt wird).

Ich weiß, dass ich den zuletzt ausgegebenen Befehl erhalten kann, indem ich dies tue

history | tail -n 1, aber history -d funktioniert nicht und ich kann keine richtige Dokumentation für zsh finden.

Alex S.
quelle

Antworten:

8

Zsh bietet keine echte History Edition-Funktion. Der Befehlsverlauf ist grundsätzlich schreibgeschützt. Alles, was Sie tun können, ist es im Großhandel zu ersetzen.

So bearbeiten Sie den Befehlszeilenverlauf:

  1. Speichern Sie es in einer Datei: fc -W
  2. Bearbeiten Sie die Datei
  3. Laden Sie den Verlauf aus der Datei: fc -R

Sie können den Dateinamen durch Festlegen auswählen HISTFILE.

Ungetesteter Code:

remove_last_history_entry () {
  setopt local_options extended_history no_hist_save_no_dups err_return

  local HISTFILE=~/.zsh_history_tmp_$$ SAVEHIST=$HISTSIZE
  fc -W
  ed -s $HISTFILE <<EOF >/dev/null
d
w
q
EOF
  fc -R
}
Gilles 'SO - hör auf böse zu sein'
quelle
5

Normalerweise können Sie die Zeile einfach entfernen ~/.zsh_history, aber wenn Sie sie nicht finden können, suchen Sie nach ~/.zshrcdem Speicherort Ihrer Verlaufsdatei.

Verwenden Sie dann einen Texteditor Ihrer Wahl, um die fehlerhaften Zeilen zu entfernen. Alternativ können Sie einfach die gesamte Datei löschen, alle zsh-Instanzen schließen und eine neue starten. Geschichte gesäubert!

kcrk
quelle
2

Also ja, das ist ein altes Thema, aber keine dieser Fragen hat es für mich beantwortet, also habe ich nur ewig versucht, das auch herauszufinden!

Hier ist meine Lösung mit Dank von @Gilles für den Hinweis, 'fc -R' und 'fc -W' zu verwenden :).

Fügen Sie das Skript darunter in Ihre .zshrc-Datei ein.

mit Quelle .zshrc neu laden

Geben Sie dann 'Vergiss' ein, um den letzten Befehl zu vergessen: D. Geben Sie 'Vergiss 3' ein, um die letzten 3 Befehle zu vergessen. Etwas sexy Shizz.

Durch Drücken des Aufwärtspfeils gelangen Sie direkt zum letzten Befehl und können sich auch nicht an das Wort "Vergessen" erinnern :).

Aktualisiert: Home-Pfad hinzugefügt, damit es jetzt in allen Verzeichnissen funktioniert lol.

Update 2: Es wurde die Möglichkeit hinzugefügt, die Anzahl der letzten Befehle zu übergeben, die Sie vergessen möchten: D. Versuchen Sie '2 vergessen', um die letzten 2 Befehle zu vergessen: D.

# Put a space at the start of a command to make sure it doesn't get added to the history.
setopt histignorespace

alias forget=' my_remove_last_history_entry' # Added a space in 'my_remove_last_history_entry' so that zsh forgets the 'forget' command :).

# ZSH's history is different from bash,
# so here's my fucntion to remove
# the last item from history.
my_remove_last_history_entry() {
    # This sub-function checks if the argument passed is a number.
    # Thanks to @yabt on stackoverflow for this :).
    is_int() ( return $(test "$@" -eq "$@" > /dev/null 2>&1); )

    # Set history file's location
    history_file="${HOME}/.zsh_history"
    history_temp_file="${history_file}.tmp"
    line_cout=$(wc -l $history_file)

    # Check if the user passed a number,
    # so we can delete x lines from history.
    lines_to_remove=1
    if [ $# -eq 0 ]; then
        # No arguments supplied, so set to one.
        lines_to_remove=1
    else
        # An argument passed. Check if it's a number.
        if $(is_int "${1}"); then
            lines_to_remove="$1"
        else
            echo "Unknown argument passed. Exiting..."
            return
        fi
    fi

    # Make the number negative, since head -n needs to be negative.
    lines_to_remove="-${lines_to_remove}"

    fc -W # write current shell's history to the history file.

    # Get the files contents minus the last entry(head -n -1 does that)
    #cat $history_file | head -n -1 &> $history_temp_file
    cat $history_file | head -n "${lines_to_remove}" &> $history_temp_file
    mv "$history_temp_file" "$history_file"

    fc -R # read history file.
}

Hier sind also ein paar Dinge los. Mit diesem Befehl können wir vor jedem Befehl ein Leerzeichen eingeben und es wird nicht zum Verlauf hinzugefügt.

setopt histignorespace

Wir können also die Leertaste drücken und 'echo hi' eingeben, die Eingabetaste drücken und wenn wir den Aufwärtspfeil drücken, ist 'echo hi' nicht in unserer Geschichte :).

Beachten Sie, dass der Alias ​​'Vergiss' ein Leerzeichen vor my_remove_last_history_entry hat. Dies ist so, dass zsh unser "Vergessen" nicht in der Geschichte speichert.

Die Funktion erklärt

ZSH verwendet fc für den Verlauf oder etwas anderes, also schreiben wir 'fc -W', um unsere aktuellen Befehle in die Verlaufsdatei zu schreiben. Mit 'head -n -1' schneiden wir den letzten Befehl aus der Datei ab. Wir speichern diese Ausgabe in einer temporären Datei und ersetzen dann die ursprüngliche Verlaufsdatei durch die temporäre. Und zum Schluss laden Sie den Verlauf mit fc -R neu.

Es gibt jedoch ein Problem mit der Funktion, das mit dem Alias ​​behoben wurde.

Wenn wir die Funktion unter ihrem Namen ausführen, wird der letzte Befehl entfernt, bei dem es sich um den Aufruf der Funktion handelt. Aus diesem Grund verwenden wir den Alias ​​mit einem Aufruf unter Verwendung eines Leerzeichens, damit zsh diesen Funktionsnamen nicht zur Verlaufsdatei hinzufügt und den letzten Eintrag zu dem gewünschten Eintrag macht: D.

Pandagoespoop
quelle
Was ist, wenn der letzte Befehl mehrzeilig war?
avp
Dies sollte als offizielle Antwort gewählt werden. Vielen Dank.
gsl
1

In zsh, stellen Sie die histignorespaceOption ( set -o histignorespace). Und bash, fügen ignorespaceoder ignoreboth(einige Distributionen bereits tun , dass in dem Standard ~/.bashrc) an $HISTCONTROLoder Satz HISTIGNORE=' *', und dann können Sie den Start aktuellen Befehls mit einem <space> vermeiden ihm der Aufnahme.

:
 : none
fc -nl -1

:

In zshkönnen Sie den vorherigen Befehl immer noch einmal aufrufen, er ist jedoch nicht im Verlauf gespeichert.

mikeserv
quelle
Dies geht nicht auf die Frage ein.
Chris Page