无法修改 command_not_found_handle 函数内的 bash 历史记录

无法修改 command_not_found_handle 函数内的 bash 历史记录

我正在尝试创建自己的command_not_found_handle函数,在给出错误的命令时,它会询问具有最相同命令的用户是否是他的意思。如果用户接受该建议,那么它应该从历史记录中删除最后一个命令(错误的命令)并添加所选的命令。但它不起作用。

这是我的代码

command_not_found_handle(){
  ....

  # replace the previous wrong command with the correct one in bash history
  history -d -1
  history -s "$command $@"
}

当我输入错误的命令并从建议中选择一个命令时,它不会修改历史记录。但是如果我自己调用该函数,例如

command_not_found_handle wrong_command

它更新历史记录,删除历史记录wrong_command并添加新历史记录。

history我通过调用函数内部的命令(返回历史列表)来验证该函数在这两种情况下都具有对历史记录的读取访问权限。但在第一种情况下,它无法写入历史。

答案1

直接使用该函数似乎是不可能的command_not_found_handle

根据man bash

如果搜索不成功,shell 将搜索名为 command_not_found_handle 的已定义 shell 函数。如果该函数存在,则会在单独的执行环境中调用它,并使用原始命令和原始命令的参数作为其参数。

history因此、等中的所有更改都variables将丢失。例如,将其包含在您的~/.bashrc

val=10

command_not_found_handle() {
  echo Val is $val
  val=50
  echo Val now is $val
}

在运行任何不存在的命令之前,您应该尝试打印以下值val

(bash shell)> echo $val
#Output
10

现在,如果您输入任何不存在的命令(例如ls4并打印),val您将得到以下结果:

(bash shell)> ls4
#Output
Val is 10
Val now is 50
(bash shell)> echo $val
#Output
10

正如您在上面看到的,最终值是,50但完成后command_not_found_handle最终值是10

发生这种情况基本上是因为它正在运行一个bash子 shell。您可以使用以下方法进行检查:

val=10

command_not_found_handle() {
  echo Val is $val
  val=50
  echo Val now is $val
  
  echo "Parent bash PID: $$"
  echo "BASH PID: $BASHPID"

  #echo $BASH_SUBSHELL #NOTE If I'm not wrong this should print `1` but 
 # it prints 0 (which is the current level of the bash parent shell). I'm not sure why.

  echo -e "\nUsing ps\n"
  ps
}

如果你运行一个不存在的命令,你会再次得到类似这样的信息:

(bash shell)> ls4
#Output
Val is 10
Val now is 50
Parent bash PID: 15399
BASH PID: 15420

Using ps

  PID TTY          TIME CMD
10561 pts/3    00:00:00 zsh
15399 pts/3    00:00:00 bash
15420 pts/3    00:00:00 bash
15421 pts/3    00:00:00 ps

正如您所看到的,它command_not_found_handle正在 shell 中运行PID: 15420。因此,变量在完成时val丢失了值。50command_not_found_handle

可能的解决方案:

你应该保存正确的命令写入文件并使用以下三种方式之一修改历史记录:

你的command_not_found_handle函数应该是这样的:

command_not_found_handle() {
  echo "$1: command not found" >&2
  read -p "What did you mean? " cmd
  echo -n "$cmd" > '/tmp/cmd.txt'
}

现在您应该创建一个函数来修改您的历史记录:

checkHist(){
   [ -f  '/tmp/cmd.txt' ] && {
      h="$(cat /tmp/cmd.txt)"
      history -d -1
      history -s "$h"
      rm '/tmp/cmd.txt'
   }
}

最后,您可以通过三个选项轻松修改历史记录:

解决方案一:使用PROMPT_COMMAND变量:

PROMPT_COMMAND='checkHist'

通过上面的代码,当执行命令时,里面的内容PROMPT_COMMAND将被执行(在本例中是checkHist函数)。所以这是最简单的方法,因为它会自动完成。

解决方案2:绑定按键/快捷键

bind -x '"\C-p":checkHis'

使用上面的代码,checkHis当您按下以下命令时,该函数将被执行:Ctrl+p

解决方案3:使用短别名

alias u="checkHist"

u使用此别名,您可以通过在终端中使用/键入该字母来修改历史记录。

相关内容