Bash

如何永久更正上一個 bash 命令中的錯字?

  • April 1, 2019

在我的 bash 互動式 shell 中輸入命令時,我打錯字的情況並不少見。我希望能夠更正我的 bash 歷史記錄中的錯字,這樣不正確的命令就不會污染它並導致我以後不小心重新執行它。特別是,我想編輯最後一個命令。

很多 問題詢問如何防止意外編輯 bash 歷史記錄 我想要相反:我想明確地編輯歷史。

根據參考問題的一些解釋,我嘗試這樣做:

$ echo foo

Up,將其更改為:

$ echo foobar

Down,但什麼也沒做,如果我再按Enter,它將執行修改後的命令並保留兩者

echo foo
echo foobar

在我的歷史中。

我知道我可以使用 手動刪除歷史條目history -d,但我還沒有設計出一種方便使用它的好方法。我不想製作一個 shell 函式來無條件地刪除最後一個歷史條目,因為我仍然希望能夠用來Up載入最後一個條目以便我可以更正它。我可以進行更正,然後刪除倒數第二個歷史條目,但這感覺很笨拙,而且對於長時間執行的命令來說尤其煩人,因為我要麼需要記住稍後執行額外的步驟,要麼需要暫時掛起它,執行這些步驟,然後繼續。

我想要的是:

  • 理想情況下,我希望能夠按Up,對我以前的命令進行更正,然後按一些特殊的鍵綁定或向命令行添加一些魔術標記,以使其在執行時替換歷史記錄條目。
  • 還可以按其他鍵序列從歷史記錄中檢索和編輯命令(類似於 Ctrl+R),該命令在執行時會覆蓋歷史記錄條目。
  • 刪除倒數第二個歷史條目的健壯shell 函式是可以容忍的,但並不理想。

我想其他人肯定也會打錯字,當這樣的命令污染他們的歷史時,他們也會同樣生氣。其他人做什麼?

HSTR看起來很吸引人,但結果對我來說有點太重了。

相反,我編寫了自己的 bash 函式:

# Removes the last command from the history that matches the given search
# string and re-executes it using the given replacement string.
#
# Usage:
#   historysub SEARCH [REPLACEMENT]
#   historysub -d SEARCH
#
#   REPLACEMENT may be omitted to remove SEARCH from the executed command.
#
#   -d removes the last command matching SEARCH from the history without
#   executing a new command.
historysub()
{
 local delete=0
 local usage=0
 local OPTIND=1
 while getopts ":hd" option; do
   case "${option}" in
     d) delete=1 ;;
     h) usage=1 ;;
     ?) usage=2 ;;
   esac
 done
 shift $((OPTIND - 1))

 local search="${1-}"
 local replacement="${2-}"

 usage_text=
 usage_text+="Usage: ${FUNCNAME[0]} SEARCH [REPLACEMENT]\n"
 usage_text+="       ${FUNCNAME[0]} -d SEARCH\n"

 if (( usage )); then
   echo -e "${usage_text}"
   return $(( usage - 1 ))
 fi

 if [[ -z "${search}" ]]; then
   echo -e "${usage_text}" >&2
   return 1
 fi

 # RE to parse the `history` output.
 local hist_re='^[ \t]*([0-9]+)[ \t]+(.+)$'

 local hist_full
 hist_full=$(HISTTIMEFORMAT="" history)

 # We don't want the search string to accidentally match against history
 # numbers, so split the `history` output so that we can search against just
 # the commands.
 local hist_nums hist_cmds
 hist_nums=$(sed -E "s/${hist_re}/\1/" <<< "${hist_full}")
 hist_cmds=$(sed -E "s/${hist_re}/\2/" <<< "${hist_full}")

 # Find the last matching history entry (excluding ourself).
 local matches last_match
 matches=$(grep -nF -- "${search}" <<< "${hist_cmds}")
 last_match=$(grep -vF -- "${FUNCNAME[0]}" <<< "${matches}" | tail -n 1)

 if [[ -z "${last_match}" ]]; then
   echo "${FUNCNAME[0]}: \"${search}\" not found." >&2
   return 1
 fi

 # RE to parse the `grep -n` output.
 local line_re='^([0-9]+):[ \t]*(.+)$'

 # Note that the line number and the history number might not be the same, so
 # we need to retrieve the original history number.
 local line_num hist_cmd hist_num
 line_num=$(sed -E "s/${line_re}/\1/" <<< "${last_match}")
 hist_cmd=$(sed -E "s/${line_re}/\2/" <<< "${last_match}")
 hist_num=$(tail -n +${line_num} <<< "${hist_nums}" | head -n 1)

 history -d "${hist_num}"
 if (( delete )); then
   echo "Removed: ${hist_cmd}"
   return 0
 fi

 local cmd="${hist_cmd/${search}/${replacement}}"
 echo "${cmd}"

 # Add the new command to the history.
 history -s -- "${cmd}"
 eval -- "${cmd}"
}

所以現在我可以執行historysub TYPO CORRECTION以重新執行帶有更正的命令。它不如能夠互動式地編輯舊命令,但我認為它應該足以滿足我的需求。

選項 #1 - 手動

我只需~/.bash_history在編輯器中打開文件,vim然後對該文件進行所需的任何更改並保存。

$ vim ~/.bash_history

在編輯它之前,確保你目前的終端歷史也被送出到這個文件:

$ history -a

請記住,您的歷史文件位於此環境變數指向的任何位置:

$ echo $HISTFILE
/Users/user1/.bash_history

選項 #2 - HSTR

有一個名為 HSTR 的 CLI 工具,您可以使用它以~/.bash_history更系統的方式管理您的文件。HSTR的主要網站是影片和使用它的詳細資訊。

它還提到了這個簡介:

HSTR 還可以管理您的命令歷史記錄(例如,您可以刪除過時或包含敏感資訊的命令)或為您喜歡的命令添加書籤。

有關更多資訊,請參閱完整文件:HSTR DOCUMENTATION

參考

引用自:https://unix.stackexchange.com/questions/456671