Mantenga solo comandos exitosos en el historial de BASH


20

A veces no entiendo la sintaxis de un comando:

# mysql -d test
mysql: unknown option '-d'
# echo $?
2

Lo intento de nuevo y lo hago bien:

# mysql --database test
Welcome to the MySQL monitor.
mysql >
...

¿Cómo evito que el primer comando, con un código de error diferente a 0, ingrese al historial?

Respuestas:


20

No creo que realmente quieras eso. Mi flujo de trabajo habitual es el siguiente:

  • Escribe un comando
  • Ejecutarlo
  • Nota que falla
  • Presione la tecla ARRIBA
  • Edite el comando
  • Ejecútalo de nuevo

Ahora, si el comando fallido no se guardara en el historial, no podría recuperarlo fácilmente para corregirlo y ejecutarlo nuevamente.


3
Supongo que un mejor diseño sería un historial de sesión y un historial permanente. ¡Gracias!
— Adam Matan

El historial se guarda al salir de la terminal. Entonces, si bien puede volver a los comandos que ha escrito en esta sesión de terminal, en realidad se guarda en el historial de bash al salir de la terminal.
— Para hacer

11

La única manera que puedo pensar para hacer esto sería utilizar history -den $PROMPT_COMMAND. El problema con este o cualquier enfoque es que es imposible saber si un comando salió con un error o se completó con éxito con un código de salida distinto de cero.

$ grep non_existent_string from_file_that_exists
$ echo $?
1

4

Es bueno tener el último comentario incorrecto para corregirlo, pero poco después se convierte en basura potencialmente confusa.

Mi enfoque es de dos pasos: almacenar comandos que fallan cuando lo hacen y eliminarlos en algún momento posterior.

Almacenar comandos que fallan cuando lo hacen:

error_handler() {
    FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}

trap error_handler ERR

trap command signalsse ejecuta commandcuando uno de ellos signalsestá "elevado".

$(command), ejecuta commandy captura su salida.

Cuando el comando falla, este fragmento de código captura el número de historial del último comando guardado en el historial y lo almacena en una variable para su eliminación futura.

Simple, pero funciona incorrectamente con HISTCONTROLy HISTIGNORE: cuando el comando no se guarda en el historial debido a una de las variables, el número de historial del último comando guardado en el historial es el comando anterior; entonces, si un comando incorrecto no se guarda en el historial, el comando anterior se eliminará.

Versión un poco más complicada, que funciona correctamente en ese caso:

debug_handler() {
    LAST_COMMAND=$BASH_COMMAND;
}

error_handler() {
    local LAST_HISTORY_ENTRY=$(history | tail -1l)

    # if last command is in history (HISTCONTROL, HISTIGNORE)...
    if [ "$LAST_COMMAND" == "$(cut -d ' ' -f 2- <<< $LAST_HISTORY_ENTRY)" ]
    then
        # ...prepend it's history number into FAILED_COMMANDS,
        # marking the command for deletion.
        FAILED_COMMANDS="$(cut -d ' ' -f 1 <<< $LAST_HISTORY_ENTRY) $FAILED_COMMANDS"
    fi
}

trap error_handler ERR
trap debug_handler DEBUG

Elimine los comandos almacenados más tarde:

exit_handler() {
    for i in $(echo $FAILED_COMMANDS | tr ' ' '\n' | uniq)
    do
        history -d $i
    done
    FAILED_COMMANDS=
}

trap exit_handler EXIT

Explicación:

Al salir de Bash, para cada número de historial único, elimine la entrada de historial correspondiente,
luego borre FAILED_COMMANDSpara no eliminar comandos que heredaron números de historial de comandos ya eliminados.

Si está seguro de que FAILED_COMMANDSestará libre de duplicados, puede iterar sobre él
(es decir, escribir for i in $FAILED_COMMANDS). Sin embargo, si espera que no se ordene de mayor a menor (en este caso, siempre lo es), reemplácelo uniqcon sort -rnu.

Los números de historial FAILED_COMMANDSdeben ser únicos y ordenados de mayor a menor, porque cuando elimina la entrada, los números de los siguientes comandos se desplazan, es decir. cuando emite history -d 2, la tercera entrada se convierte en la segunda, la cuarta se convierte en la tercera, etc.

Debido a que, al utilizar este código, no se puede llamar de forma manual history -d <n>
, donde nes menor o igual al mayor número almacenado enFAILED_COMMANDS
y esperar que el código funcione correctamente.

Es probablemente una buena idea conectar exit_handlera EXIT, pero también se puede llamar en cualquier momento anterior.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.