Conserva solo i comandi riusciti nella cronologia BASH


20

A volte fraintendo la sintassi di un comando:

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

Riprovo e ho capito bene:

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

Come posso impedire al primo comando, con codice di errore diverso da 0, di inserire la cronologia?

Risposte:


20

Non penso che tu lo voglia davvero. Il mio solito flusso di lavoro va così:

  • Digita un comando
  • Eseguirlo
  • Notare che fallisce
  • Premere il tasto SU
  • Modifica il comando
  • Eseguilo di nuovo

Ora, se il comando fallito non fosse stato salvato nella cronologia, non avrei potuto ripristinarlo facilmente ed eseguirlo di nuovo.


3
Immagino che un design migliore sarebbe una cronologia delle sessioni e una cronologia permanente. Grazie!
Adam Matan,

La cronologia viene salvata quando si esce dal terminale. Quindi, mentre puoi tornare ai comandi che hai digitato in questa sessione del terminale, in realtà viene salvato nella cronologia di bash all'uscita dal terminale.
Da fare il

11

L'unico modo che posso pensare di farlo sarebbe quello di utilizzare history -din $PROMPT_COMMAND. Il problema con questo o qualsiasi approccio è che è impossibile stabilire se un comando è uscito con un errore o è stato completato correttamente con un codice di uscita diverso da zero.

$ grep non_existent_string from_file_that_exists
$ echo $?
1

4

È utile avere l'ultimo commento errato per correggerlo, ma subito dopo diventa spazzatura potenzialmente confusa.

Il mio approccio è in due passaggi: memorizza i comandi che falliscono quando lo fanno e li rimuove più tardi.

Memorizza i comandi che falliscono quando lo fanno:

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

trap error_handler ERR

trap command signalsviene eseguito commandquando uno di signalsè "sollevato".

$(command), esegue commande acquisisce il suo output.

Quando il comando non riesce, questo frammento di codice acquisisce il numero di cronologia dell'ultimo comando salvato nella cronologia e lo memorizza in una variabile per la futura cancellazione.

Semplice, ma funziona in modo errato con HISTCONTROLe HISTIGNORE- quando il comando non viene salvato nella cronologia a causa di una delle variabili, il numero di cronologia dell'ultimo comando salvato nella cronologia è quello del comando precedente; quindi, se un comando errato non viene salvato nella cronologia, il comando precedente verrà eliminato.

Versione leggermente più complicata, che funziona correttamente in quel 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

Rimuovi i comandi memorizzati qualche tempo dopo:

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

trap exit_handler EXIT

Spiegazione:

All'uscita da Bash, per ogni numero di cronologia univoco rimuovere la corrispondente voce di cronologia,
quindi deselezionare FAILED_COMMANDSper non rimuovere i comandi che hanno ereditato i numeri di cronologia da comandi già eliminati.

Se sei sicuro che FAILED_COMMANDSsarà privo di duplicati, puoi semplicemente iterare su di esso
(es. Scrivere for i in $FAILED_COMMANDS). Se, tuttavia, ti aspetti che non sia ordinato dal più grande al più piccolo (in questo caso lo è sempre), sostituiscilo uniqcon sort -rnu.

I numeri di cronologia FAILED_COMMANDSdevono essere univoci e ordinati dal più grande al più piccolo, perché quando si elimina la voce, i numeri dei comandi successivi vengono spostati, ad es. quando si emette history -d 2, la terza voce diventa seconda, la quarta diventa terza, ecc.

A causa di ciò, quando si utilizza questo codice, non è possibile chiamare manualmente history -d <n>
dove nè minore o uguale al maggior numero memorizzato inFAILED_COMMANDS
e si aspettano il codice per funzionare correttamente.

E 'probabilmente una buona idea di agganciare exit_handlera EXIT, ma si può anche chiamare in qualsiasi momento prima.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.