履歴をたどるコマンドラインに自分のコードをどのように配置できますか?

履歴をたどるコマンドラインに自分のコードをどのように配置できますか?

さまざまなテキストファイルに、何百ものテストされ試みられたコマンドとフラグメントが格納されています。再利用する必要がある場合は、見つけてコマンドラインにコピーして貼り付けます。信頼できますが、これは不器用なアプローチです。これとは対照的に、履歴ファイルから以前のコマンドをコマンドラインで直接検索して、編集および使用の準備をすることができます。この機能をエミュレートして独自のコマンドセットを使用するにはどうすればよいですか?

fzfを使って検索し、私のコマンドを見つけて履歴ファイルに追加するスクリプトがあります。これは素晴らしい作品です。しかし、それは歴史的な文書を混乱させる。

これは私のスクリプトです。

find ~ -type f | fzf --preview-window=up:50% --header "ENTER:less; ^s:snip to history" --bind "enter:execute(less {})"  --bind "ctrl-s:execute(cat {} | fzf -m --preview-window=:hidden  >>~/.bash_history)"; history -n

答え1

インタラクティブBashのための迅速で簡単な設定(my bash --versionprint 5.2.15):

  1. 必要な(1行)コマンドを~/.commands

  2. 次のヘルパー関数を定義します。

    _get_command () {
       READLINE_LINE="$(<~/.commands fzf -1 --query="$READLINE_LINE")" &&
       READLINE_POINT="${#READLINE_LINE}"
    }
    
  3. キーへのバインディング(キーシーケンス):

    bind -x '"\C-x\C-r":_get_command'
    
  4. Ctrl+ xCtrl+で始めましょうr

メモ:

  • READLINE_POINT="${#READLINE_LINE}"カーソルは最後に配置する必要があります。 Bash 5は文字の長さを望み、上記のコードは機能しますが、Bash 4はバイトが必要です。 Bash 4で非ASCIIテキストを処理するには、次のようにします。

    READLINE_POINT="$(printf '%s' "$READLINE_LINE" | wc -c)"
    

    (私は - から来ましたこの回答)。

  • ~/.commandsこれは、各コマンドの目的のカーソル位置を指定またはエンコードするために独自のフォーマットを作成できるためです。あなたのフォーマットに従って設定できるようにヘルパー機能が強化されましたREADLINE_LINEREADLINE_POINT

    一方、~/.commands保存専用リテラルコマンドは次のとおりです。シンプルそして--query="$READLINE_LINE"

  • 複数行コマンドの場合fzf --read0と null で終わる項目が必要です~/.commands。この形式を維持することは、改行文字で終わる項目を編集するよりも困難です。


上記を作成した後、この機能が必要だと判断しました。より複雑な解決策は次のとおりです~/.bashrc

export SNIPPETFILE

_del_snippet () {
   SNIPPETFILE="${SNIPPETFILE:-"$HOME/.snippets"}"
   printf '%s\0' "$1" | sort -zm -- "$SNIPPETFILE" - | uniq -zu >"$SNIPPETFILE"~ \
   && mv -- "$SNIPPETFILE"~ "$SNIPPETFILE"
   cat -- "$SNIPPETFILE"
}
export -f _del_snippet

_get_snippet () {
   SNIPPETFILE="${SNIPPETFILE:-"$HOME/.snippets"}"
   local line
   line="$(<"$SNIPPETFILE" fzf -1 --read0 --query="$READLINE_LINE" \
      --border top --border-label 'Enter to confirm, Ctrl+y to delete entry, Ctrl+c to abort' \
      --bind 'ctrl-y:reload-sync(exec bash -c "_del_snippet \"\$1\"" bash {})')" \
   && READLINE_LINE="$line" \
   && READLINE_POINT="${#READLINE_LINE}"
}
bind -x '"\C-x\C-r":_get_snippet'

_put_snippet () {
   [[ "$READLINE_LINE" =~ ^[[:space:]]*$ ]] && return 0
   SNIPPETFILE="${SNIPPETFILE:-"$HOME/.snippets"}"
   if
      touch -- "$SNIPPETFILE" \
      && printf '%s\0' "$READLINE_LINE" | sort -zum -- "$SNIPPETFILE" - >"$SNIPPETFILE"~ \
      && mv -- "$SNIPPETFILE"~ "$SNIPPETFILE"
   then
      printf 'command stored in `%s'\''\n' "$SNIPPETFILE" >&2
   else
      printf 'storing in `%s'\'' failed\n' "$SNIPPETFILE" >&2
      return 1
   fi
}
bind -x '"\C-x\C-m":_put_snippet'

使用法:

  • Ctrl+ xCtrl+を使用して現在のコマンドラインを保存しますm

  • Ctrl+ xCtrl+を使用して保存したrコマンドのリストから選択します。すでに入力した内容と正確に一致するものがある場合は、コマンドラインに移動します。より多くの場合、インタラクティブに選択できます。

  • インタラクティブに選択すると、Ctrl+はy強調表示された項目を削除します。

メモ:

  • 複数行コマンドはサポートされていますが、正しく保存するためにクリックすることはできませんEnter(引用符の内側または後ろ\)。それ以外の場合は、セカンダリプロンプトが表示されます。履歴から複数行のコマンドをインポートするか、Ctrl+ v、+を押してコマンドをCtrl複数行にすることで、jセカンダリプロンプトが表示されずにコマンド全体を編集できます。その後、Ctrl+ xCtrl+はm複数行のコマンド全体を保存できます。

    これらの行をインタラクティブに選択すると、複数行のコマンドのようには見えませんが、複数行でコマンドラインに表示されます。

    ここには良い副作用があります。ラベル付きコマンドを保存できます。これ

    # description (label) here
    :
    actual_command args
    

    リストは次のとおりです。

    # description (label) here : actual_command args
    

    しかし、選択した後は動作します。

  • デフォルトのファイルはです$HOME/.snippetsexportという変数を設定して使用して、別のパス名を使用できますSNIPPETFILE。後にチルダがあるパス名(例$HOME/.snippets~:)もメンテナンスに使用されます。

  • Bash 5.2.15でGNUとGNUでsortテストされていますuniq(移植可能ではないオプションを使用)。

  • それでもエラーがある可能性があります。

答え2

問題を解決するには、xdotoolを探索する価値があります。

マニュアルページによると:

xdotoolを使用すると、キーボード入力やマウスアクティビティをプログラム的に(または手動で)シミュレートし、ウィンドウを移動してサイズを変更するなどの操作を実行できます。

したがって、お気に入りのコマンドを見つけるのに役立つエイリアスを定義し、xdotoolにコマンドラインに配置するように指示できます。たとえば、

$ alias my_command='stty -echo &&  xdotool type "$(cat any_list | fzf)" ; stty echo'

これにより、「any_list」ファイルからテキスト行を抽出してコマンドラインに配置できます。そのテキストが前のコマンドの1つである場合は、そのテキストを編集して実行できます。

現在の設定にすでにxdotoolがある可能性があります。そうでなければ、ダウンロードしてインストールするのはとても簡単です。https://installati.one/install-xdotool-debian-12

答え3

存在するbashshell-expand-line(キーボードショートカットM-C-e、通常++ ALT)は、「シェルのように行を拡張します。これは、すべてのシェルワード拡張だけでなく、エイリアスと履歴拡張も実行します。」CTRLe

したがって、目的を達成する最も簡単な方法は、コマンドラインに挿入したいコマンドをいくつかの変数に割り当て、変数名を書き、このキーシーケンスを押して内容を展開することです。

たとえば、

$ COMMAND="echo hello world"

次に、コマンドラインに変数名($COMMANDこの場合)を書き、ALT++CTRLを押しますe$COMMAND現在行の内容に自動的に置き換えられます。

$ echo hello world

$(!!)または、シーケンスを作成してクリックして、コマンドラインを前のコマンドの出力に置き換えることもできます。たとえば、

$ grep ps .snippets
ps -fp $$
$ $(!!)

その時点でALT+をクリックすると、コマンドラインがコマンド出力に置き換えられますCTRLegrep

$ ps -fp $$

関連情報