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

検索に失敗すると、シェルはcommand_not_found_handleという定義されたシェル関数を検索します。関数が存在する場合は、元のコマンドと元のコマンドの引数を引数として別々の実行環境で呼び出されます。

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。以下を使用して確認できます。

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で実行していますPID: 15420。したがって、変数は完了するとvalその値を失います。50command_not_found_handle

考えられる解決策:

あなたは保存する必要があります正しいこのコマンドはファイルに書き込み、次の3つの方法のいずれかで履歴を変更します。

関数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'
   }
}

最後に、次の3つのオプションを使用して履歴を簡単に変更できます。

解決策1:変数の使用PROMPT_COMMAND:

PROMPT_COMMAND='checkHist'

上記のコードを使用すると、命令の実行時に内部の内容(この場合は関数)がPROMPT_COMMAND実行されます。checkHist自動的に行われるので、これが最も簡単な方法です。

解決策2:バインディングキー/ショートカット

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

上記のコードを使用してcheckHis次のコマンドを押すと、関数が実行されます。Ctrl+p

解決策3:短いエイリアスの使用

alias u="checkHist"

uこのエイリアスを使用すると、端末でその文字を使用/入力して履歴を変更できます。

関連情報