Behalten Sie nur erfolgreiche Befehle im BASH-Verlauf

Behalten Sie nur erfolgreiche Befehle im BASH-Verlauf

Manchmal verstehe ich die Syntax eines Befehls falsch:

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

Ich versuche es noch einmal und mache es richtig:

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

Wie verhindere ich, dass der erste Befehl mit einem Fehlercode ungleich 0 in den Verlauf aufgenommen wird?

Antwort1

Ich glaube nicht, dass Sie das wirklich wollen. Mein üblicher Arbeitsablauf sieht folgendermaßen aus:

  • Geben Sie einen Befehl ein
  • Starte es
  • Beachten Sie, dass es fehlschlägt
  • Drücken Sie die Taste UP
  • Bearbeiten des Befehls
  • Führen Sie es erneut aus

Wenn der fehlgeschlagene Befehl nicht im Verlauf gespeichert wäre, könnte ich ihn nicht einfach wiederherstellen, um ihn zu reparieren und erneut auszuführen.

Antwort2

Die einzige Möglichkeit, die mir hierfür einfällt, wäre die Verwendung von history -din $PROMPT_COMMAND. Das Problem bei diesem oder jedem anderen Ansatz besteht darin, dass es unmöglich ist, festzustellen, ob ein Befehl mit einem Fehler beendet wurde oder erfolgreich mit einem Exit-Code ungleich Null abgeschlossen wurde.

$ grep non_existent_string from_file_that_exists
$ echo $?
1

Antwort3

Es ist gut, den letzten falschen Kommentar zu haben, um ihn zu korrigieren, aber kurz danach wird er zu potenziell verwirrendem Müll.

Mein Ansatz besteht aus zwei Schritten: Speichern Sie fehlgeschlagene Befehle, wenn dies der Fall ist, und entfernen Sie sie zu einem späteren Zeitpunkt.

Speichern Sie Befehle, die fehlschlagen, wenn dies der Fall ist:

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

trap error_handler ERR

trap command signalswird ausgeführt command, wenn eines von signals„erhöht“ wird.

$(command), führt aus commandund erfasst seine Ausgabe.

Wenn der Befehl fehlschlägt, erfasst dieser Codeausschnitt die Verlaufsnummer vonletzter Befehl im Verlauf gespeichert, und speichert es in einer Variablen zum späteren Löschen.

Einfach, funktioniert aber nicht richtig mit HISTCONTROLund HISTIGNORE– wenn der Befehl aufgrund einer der Variablen nicht im Verlauf gespeichert wird,Verlaufsnummer des letzten im Verlauf gespeicherten Befehlsist der vorherige Befehl. Wenn also der falsche Befehl nicht im Verlauf gespeichert wird, wird der vorherige Befehl gelöscht.

Etwas kompliziertere Version, die in diesem Fall korrekt funktioniert:

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

Gespeicherte Befehle zu einem späteren Zeitpunkt entfernen:

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

trap exit_handler EXIT

Erläuterung:

Entfernen Sie beim Beenden von Bash für jede eindeutige Verlaufsnummer den entsprechenden Verlaufseintrag und
löschen Sie dann die FAILED_COMMANDSOption, um Befehle nicht zu entfernen, die Verlaufsnummern von bereits gelöschten Befehlen geerbt haben.

Wenn Sie sicher sind, dass es FAILED_COMMANDSkeine Duplikate enthält, können Sie einfach darüber iterieren
(d. h. schreiben for i in $FAILED_COMMANDS). Wenn Sie jedoch erwarten, dass es nicht von groß nach klein sortiert ist (in diesem Fall ist es das immer), ersetzen Sie es uniqdurch sort -rnu.

Die Verlaufsnummern FAILED_COMMANDSmüssen eindeutig sein und von der größten zur kleinsten sortiert werden, da beim Löschen eines Eintrags die Nummern der nächsten Befehle verschoben werden – wenn Sie beispielsweise eingeben history -d 2, wird der 3. Eintrag zum 2., der 4. zum 3. usw.

Aus diesem Grund können Sie bei Verwendung dieses Codes nicht manuell aufrufen, history -d <n>
wobei ndie Zahl kleiner oder gleich der größten gespeicherten Zahl ist,FAILED_COMMANDS
und erwarten, dass der Code ordnungsgemäß funktioniert.

exit_handlerEs ist wahrscheinlich eine gute Idee, bei einzuhaken EXIT, aber Sie können es auch jederzeit früher aufrufen.

verwandte Informationen