AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 456671
Accepted
jamesdlin
jamesdlin
Asked: 2018-07-17 18:40:42 +0800 CST2018-07-17 18:40:42 +0800 CST 2018-07-17 18:40:42 +0800 CST

如何永久更正上一个 bash 命令中的错字?

  • 772

在我的 bash 交互式 shell 中输入命令时,我打错字的情况并不少见。我希望能够更正我的 bash 历史记录中的错字,这样不正确的命令就不会污染它并导致我以后不小心重新执行它。特别是,我想编辑最后一个命令。

有很多 问题询问如何防止意外编辑 bash 历史记录。 我想要相反:我想明确地编辑历史。

根据参考问题的一些解释,我尝试这样做:

$ echo foo

按Up,将其更改为:

$ echo foobar

按Down,但什么也没做,如果我再按Enter,它将执行修改后的命令并保留两者

echo foo
echo foobar

在我的历史中。

我知道我可以使用 手动删除历史条目history -d,但我还没有设计出一种方便使用它的好方法。我不想制作一个 shell 函数来无条件地删除最后一个历史条目,因为我仍然希望能够用来Up加载最后一个条目以便我可以更正它。我可以进行更正,然后删除倒数第二个历史条目,但这感觉很笨拙,而且对于长时间运行的命令来说尤其烦人,因为我要么需要记住稍后执行额外的步骤,要么需要暂时挂起它,执行这些步骤,然后继续。

我想要的是:

  • 理想情况下,我希望能够按Up,对我以前的命令进行更正,然后按一些特殊的键绑定或向命令行添加一些魔术标记,以使其在执行时替换历史记录条目。

  • 还可以按其他键序列从历史记录中检索和编辑命令(类似于 Ctrl+R),该命令在执行时会覆盖历史记录条目。

  • 删除倒数第二个历史条目的健壮shell 函数是可以容忍的,但并不理想。

我想其他人肯定也会打错字,当这样的命令污染他们的历史时,他们也会同样生气。其他人做什么?

bash command-history
  • 2 2 个回答
  • 761 Views

2 个回答

  • Voted
  1. slm
    2018-07-17T18:45:04+08:002018-07-17T18:45:04+08:00

    选项 #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。

    参考

    • 从 Bash 历史文件中删除某行
    • 4
  2. Best Answer
    jamesdlin
    2018-10-07T11:20:18+08:002018-10-07T11:20:18+08:00

    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以重新执行带有更正的命令。它不如能够交互式地编辑旧命令,但我认为它应该足以满足我的需求。

    • 0

相关问题

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 从文本文件传递变量的奇怪问题

  • 虽然行读取保持转义空间?

  • `tee` 和 `bash` 进程替换顺序

  • 运行一个非常慢的脚本直到它成功

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    ssh 无法协商:“找不到匹配的密码”,正在拒绝 cbc

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    如何卸载内核模块“nvidia-drm”?

    • 13 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add 返回:“连接代理时出错:没有这样的文件或目录” 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya 为什么 Linux 使用 LF 作为换行符? 2017-12-20 05:48:21 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve