Às vezes eu entendo mal a sintaxe de um comando:
# mysql -d test
mysql: unknown option '-d'
# echo $?
2
Tento novamente e acerto:
# mysql --database test
Welcome to the MySQL monitor.
mysql >
...
Como evito que o primeiro comando, com código de erro diferente de 0, entre no histórico?
Responder1
Eu não acho que você realmente queira isso. Meu fluxo de trabalho normal é assim:
- Digite um comando
- Executá-lo
- Observe que está falhando
- Pressione a tecla PARA CIMA
- Edite o comando
- Execute novamente
Agora, se o comando com falha não fosse salvo no histórico, não seria possível recuperá-lo facilmente para corrigi-lo e executá-lo novamente.
Responder2
A única maneira que consigo pensar em fazer isso seria usar history -d
in $PROMPT_COMMAND
. O problema com esta ou qualquer abordagem é que é impossível saber se um comando foi encerrado com um erro ou concluído com êxito com um código de saída diferente de zero.
$ grep non_existent_string from_file_that_exists
$ echo $?
1
Responder3
É bom ter o último comentário incorreto para corrigi-lo, mas logo depois disso, torna-se um lixo potencialmente confuso.
Minha abordagem consiste em duas etapas: armazenar comandos que falham e removê-los algum tempo depois.
Armazene comandos que falham quando isso acontece:
error_handler() {
FAILED_COMMANDS="$(history | tail -1l | cut -c -5) $FAILED_COMMANDS"
}
trap error_handler ERR
trap command signals
é executado command
quando um deles signals
é "aumentado".
$(command)
, executa command
e captura sua saída.
Quando o comando falha, este trecho de código captura o número histórico deúltimo comando salvo no históricoe armazena-o em uma variável para exclusão futura.
Simples, mas funciona incorretamente com HISTCONTROL
e HISTIGNORE
– quando o comando não é salvo no histórico devido a uma das variáveis,número do histórico do último comando salvo no históricoé o comando anterior; portanto, se o comando incorreto não for salvo no histórico, o comando anterior será excluído.
Versão um pouco mais complicada, que funciona corretamente nesse 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
Remova os comandos armazenados algum tempo depois:
exit_handler() {
for i in $(echo $FAILED_COMMANDS | tr ' ' '\n' | uniq)
do
history -d $i
done
FAILED_COMMANDS=
}
trap exit_handler EXIT
Explicação:
Ao sair do Bash, para cada número de histórico exclusivo, remova a entrada de histórico correspondente e
desmarque FAILED_COMMANDS
para não remover comandos que herdaram números de histórico de comandos já excluídos.
Se tiver certeza de que FAILED_COMMANDS
estará livre de duplicatas, você pode simplesmente iterá-lo
(ou seja, write for i in $FAILED_COMMANDS
). Se, no entanto, você espera que não seja classificado do maior para o menor (nesse caso, sempre é), substitua uniq
por sort -rnu
.
Os números do histórico FAILED_COMMANDS
devem ser únicos e classificados do maior para o menor, porque quando você exclui uma entrada, os números dos próximos comandos são alterados - ou seja. quando você emite history -d 2
, a 3ª entrada se torna a 2ª, a 4ª se torna a 3ª, etc.
Por isso, ao usar este código, você não pode chamar manualmente history -d <n>
onde n
for menor ou igual ao maior número armazenadoFAILED_COMMANDS
e esperar que o código funcione corretamente.
Provavelmente é uma boa ideia ligar exit_handler
para EXIT
, mas você também pode ligar a qualquer momento antes.