僅在 BASH 歷史記錄中保留成功的命令

僅在 BASH 歷史記錄中保留成功的命令

有時我會誤解指令的語法:

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

我再試一次並得到正確的結果:

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

如何防止錯誤代碼不為 0 的第一條命令進入歷史記錄?

答案1

我不認為你真的想要那樣。我平常的工作流程是這樣的:

  • 輸入命令
  • 運行
  • 注意它失敗了
  • 按向上鍵
  • 編輯命令
  • 再次運行

現在,如果失敗的命令沒有保存到歷史記錄中,我就無法輕鬆地將其修復並再次運行。

答案2

我能想到的唯一方法是使用history -din $PROMPT_COMMAND。這種方法或任何方法的問題在於,無法判斷命令是否因錯誤退出或以非零退出代碼成功完成。

$ grep non_existent_string from_file_that_exists
$ echo $?
1

答案3

最好能有最後一個錯誤的評論來糾正它,但不久之後,它就會變成潛在的令人困惑的垃圾。

我的方法分為兩個步驟:儲存失敗的命令,並在稍後刪除它們。

儲存失敗的命令:

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

trap error_handler ERR

trap command signalscommand當其中一個signals被“引發”時執行。

$(command),執行command並捕獲其輸出。

當命令失敗時,這段程式碼會捕捉歷史數量最後一條命令保存到歷史記錄中,並將其儲存在變數中以供將來刪除。

簡單,但與HISTCONTROLand一起使用時無法正常工作HISTIGNORE– 當由於其中一個變數而未將命令保存到歷史記錄中時,保存到歷史中的最後命令的歷史編號是上一個命令的命令;因此,如果錯誤的命令沒有儲存到歷史記錄中,則先前的命令將被刪除。

稍微複雜一點的版本,在這種情況下可以正常工作:

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

稍後刪除儲存的命令:

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

trap exit_handler EXIT

解釋:

退出 Bash 時,對於每個唯一的歷史記錄編號,刪除對應的歷史記錄條目,
然後清除FAILED_COMMANDS以不刪除從已刪除的命令繼承歷史記錄編號的命令。

如果您確定它FAILED_COMMANDS不會重複,您可以簡單地對其進行迭代
(即 write for i in $FAILED_COMMANDS)。但是,如果您希望它不是從最大到最小排序(在本例中始終如此),請替換uniqsort -rnu

歷史記錄中的編號FAILED_COMMANDS必須是唯一的,並且從大到小排序,因為當您刪除條目時,下一個命令的編號會發生變化 - 即。當您發出 時history -d 2,第 3 個條目變為第 2 個條目,第 4 個條目變為第 3 個條目,依此類推。

因此,在使用此程式碼時,您無法手動呼叫history -d <n>
wheren小於或等於儲存的最大數字FAILED_COMMANDS
並期望程式碼正常運作。

exit_handler掛接可能是個好主意EXIT,但您也可以提前隨時呼叫它。

相關內容