A veces entiendo mal 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 código de error diferente a 0, ingrese al historial?
Respuesta1
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
- Editar el comando
- Ejecútelo de nuevo
Ahora, si el comando fallido no se guarda en el historial, no podría recuperarlo fácilmente para arreglarlo y ejecutarlo nuevamente.
Respuesta2
La única forma que se me ocurre de hacer esto sería utilizar history -d
in $PROMPT_COMMAND
. El problema con este o cualquier enfoque es que es imposible saber si un comando salió con un error o se completó exitosamente con un código de salida distinto de cero.
$ grep non_existent_string from_file_that_exists
$ echo $?
1
Respuesta3
Es bueno tener el último comentario incorrecto para corregirlo, pero poco después se convierte en basura potencialmente confusa.
Mi enfoque consta de dos pasos: almacenar los comandos que fallan cuando lo hacen y eliminarlos más tarde.
Almacene los comandos que fallan cuando lo hacen:
error_handler() {
FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}
trap error_handler ERR
trap command signals
se ejecuta command
cuando uno de signals
es "elevado".
$(command)
, ejecuta command
y captura su salida.
Cuando el comando falla, este fragmento de código captura el número histórico deúltimo comando guardado en el historialy lo almacena en una variable para su futura eliminación.
Simple, pero funciona incorrectamente con HISTCONTROL
yHISTIGNORE
– cuando el comando no se guarda en el historial debido a una de las variables,número de historial del último comando guardado en el historiales el del comando anterior; por lo tanto, si el 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 adelante:
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 del historial correspondiente,
luego borre FAILED_COMMANDS
para no eliminar los comandos que heredaron números de historial de comandos ya eliminados.
Si está seguro de que FAILED_COMMANDS
estará libre de duplicados, puede simplemente iterarlo
(es decir, escribir for i in $FAILED_COMMANDS
). Sin embargo, si espera que no esté ordenado de mayor a menor (en este caso siempre lo está), reemplácelo uniq
con sort -rnu
.
Los números del historial FAILED_COMMANDS
deben ser únicos y estar ordenados de mayor a menor, porque cuando elimina una 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.
Por eso, al utilizar este código, no puede llamar manualmente history -d <n>
a dónde n
es menor o igual que el mayor número almacenadoFAILED_COMMANDS
y esperar que el código funcione correctamente.
Probablemente sea una buena idea conectarte exit_handler
a EXIT
, pero también puedes llamarlo en cualquier momento antes.