Cómo eliminar el último comando (o comando actual para bonificación) del historial de zsh

13

Claro que hay una manera súper simple e inteligente de hacer esto, pero dado que el historial en zshell parece estar alias a fc, no hay forma de usar los trucos mencionados en ¿Cómo eliminar una sola línea del historial? .

¿Alguna sugerencia sobre cómo hacer esto? Mi caso de uso sería eliminar el último comando emitido del historial para que detenga el autocompletado (principalmente cuando ha escrito mal algo y sigue apareciendo).

Sé que puedo obtener el último comando emitido haciendo

history | tail -n 1, pero history -d no funciona y no puedo encontrar la documentación adecuada para zsh.

Alex S
fuente

Respuestas:

8

Zsh no ofrece una instalación de edición de historia real. El historial de comandos es básicamente de solo lectura. Todo lo que puedes hacer es reemplazarlo al por mayor.

Para editar el historial de la línea de comando:

  1. Guárdelo en un archivo: fc -W
  2. Edite el archivo
  3. Cargue el historial desde el archivo: fc -R

Puede elegir el nombre del archivo mediante la configuración HISTFILE.

Código no probado:

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- deja de ser malvado'
fuente
6

Por lo general, puede eliminar la línea ~/.zsh_history, pero si no puede encontrarla, busque ~/.zshrcla ubicación de su archivo de historial.

Luego use cualquier editor de texto de su elección para eliminar las líneas ofensivas. Alternativamente, simplemente elimine todo el archivo y cierre todas las instancias de zsh e inicie una nueva. ¡Historia purgada!

kcrk
fuente
2

Así que sí, este es un tema antiguo, pero ninguna de estas preguntas me respondió, ¡así que pasé años tratando de resolver esto también!

Aquí está mi solución gracias a @Gilles por la sugerencia de usar 'fc -R' y 'fc -W' :).

Pegue el script debajo de esto en su archivo .zshrc.

recargar con la fuente .zshrc

luego escriba 'olvidar' para olvidar el último comando: D. escriba 'olvidar 3' para olvidar los últimos 3 comandos. Un poco de sexy shizz.

Presionando la flecha hacia arriba lo llevará directamente al último comando y tampoco recordará la palabra 'olvidar' :).

Actualizado: Se agregó la ruta de inicio, por lo que funciona en todos los directorios ahora lol.

Actualización 2: Se agregó la capacidad de pasar el número de últimos comandos que desea olvidar: D. Intente 'olvidar 2' para olvidar los últimos 2 comandos: 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.
}

Así que hay algunas cosas pasando aquí. Este comando nos permitirá escribir un espacio antes de cualquier comando, y no se agregará al historial.

setopt histignorespace

Entonces, podemos presionar la barra espaciadora y escribir 'echo hola', presionar enter y cuando presionamos la flecha hacia arriba, 'echo hola' no está en nuestra historia :).

Observe cómo el alias 'olvidar' tiene un espacio antes de my_remove_last_history_entry. Esto es para que zsh no guarde nuestro 'olvidar' en la historia.

La función explicada

ZSH usa fc para el historial o algo así, por lo que hacemos 'fc -W' para escribir nuestros comandos actuales en el archivo de historial, en ellos usamos 'head -n -1' para recortar el último comando del archivo. Guardamos esa salida en un archivo temporal y luego reemplazamos el archivo de historial original por el temporal. Y finalmente recargar el historial con fc -R.

Sin embargo, hay un problema con la función que se corrige con el alias.

Si ejecutamos la función por su nombre, eliminará el último comando, que es la llamada a la función. Es por eso que usamos el alias con una llamada usando un espacio, para que zsh no agregue este nombre de función al archivo de historial, haciendo que la última entrada sea la que queremos: D.

pandagoespoop
fuente
¿Qué pasa si el último comando fue de varias líneas?
avp
Esto debería ser votado como la respuesta oficial. Gracias.
GSL
1

En zsh, establezca la histignorespaceopción ( set -o histignorespace). Y en bash, agregue ignorespaceo ignoreboth(algunas distribuciones ya lo hacen de manera predeterminada ~/.bashrc) $HISTCONTROLo establezca HISTIGNORE=' *', y luego puede iniciar el comando actual con un <space> para evitar grabarlo.

:
 : none
fc -nl -1

:

En zsh, aún puede recuperar ese comando anterior una vez, pero no está almacenado en el historial.

mikeserv
fuente
Esto no responde a la pregunta.
Chris Page