正規表現による逆履歴検索


10

単純な正規表現(または複数の一致)をサポートする逆増分検索を可能にするツールを探しています。たとえば、「foo bar baz」というコマンドを見つけたい場合は、次のようにしてコマンドをすばやく見つけることができます。

CRTL-R(検索を開始)タイプ 'foo'(fooを使用する最新のコマンドと一致) 'foo | baz'( 'foo' AND 'baz'を含む最新のコマンドと一致)の入力を続行

このようなものはありますか?いいえの場合、どうすれば自分で実装できますか?

回答:


4

カスタムウィジェットhistory-incremental-multi-searchのためにzsh

セットアップ

ディレクトリを作成してそれをに含める$fpathたとえば、私はディレクトリを作成し、~/.zsh/functionsその行fpath=($HOME/.zsh/functions $fpath)をmy に作成します.zshrc

history-incremental-multi-searchそのディレクトリにある名前のファイルに以下を配置します。

emulate -L zsh
setopt extended_glob

local oldbuffer=$BUFFER
local -i oldcursor=$CURSOR

local dir                # search direction
local chars              # input buffer
local -a words           # search terms
local -a found           # all history items that match first term
local -i hindex=$HISTNO  # current 
local -i lmatch          # last matched history item (for prev/next)

if [[ $WIDGET == *forward* ]]; then
    dir=fwd
else
    dir=bck
fi

function find-next {
    # split the input buffer on spaces to get search terms
    words=(${(s: :)chars})

    # if we have at least one search term
    if (( $#words )); then
        # get all keys of history items that match the first
        found=(${(k)history[(R)*$words[1]*]})
        if (( $#found )); then
            # search in widget direction by default
            # but accept exception in $1 for "prev match"
            search-${1:-$dir}
        else
            # no matches
            lmatch=$HISTNO
        fi
    else
        # no search terms
        lmatch=$HISTNO
        BUFFER=$oldbuffer
        CURSOR=$oldcursor
    fi
}

function search-fwd {
    # search forward through matches
    local -i i
    for (( i = $#found; i > 0; i-- )); do
        # but not before hindex as we're searching forward
        if [[ $found[$i] -gt $hindex ]]; then
            set-match $found[$i]
        fi
    done
}

function search-bck {
    # search backward through matches
    local -i i
    for (( i = 1; i <= $#found; i++ )); do
        # but not beyond hindex as we're searching backward
        if [[ $found[$i] -lt $hindex ]]; then
            set-match $found[$i]
        fi
    done
}

function set-match {
    # match history item against all terms and select it if successful
    local match=1
    local -i i
    for (( i = 2; i <= $#words; i++ )); do
        if [[ $history[$1] != *$words[$i]* ]]; then
            match=0
            break
        fi
    done
    if [[ $match -ne 0 ]]; then
        lmatch=$1
        BUFFER=$history[$1]
        CURSOR=$#BUFFER
        break
    fi
}

# display sub prompt
zle -R "${dir}-i-search-multi:"

# handle input keys
while read -k; do
    case $REPLY in
        # next
        $'\C-n' )
            hindex=$lmatch
            find-next
            ;;
        # prev
        $'\C-p' )
            hindex=$lmatch
            if [[ $dir == fwd ]]; then
                find-next bck
            else
                find-next fwd
            fi
            ;;
        # break
        $'\e' | $'\C-g' )
            BUFFER=$oldbuffer
            CURSOR=$oldcursor
            break
            ;;
        # accept
        $'\C-m' | $'\C-j' )
            if [[ $lmatch -eq $HISTNO ]]; then
                BUFFER=$oldbuffer
                CURSOR=$oldcursor
            else
                HISTNO=$lmatch
            fi
            break
            ;;
        # erase char
        $'\C-h' | $'\C-?' )
            chars=$chars[1,-2]
            hindex=$HISTNO
            find-next
            ;;
        # erase word
        $'\C-w' )
            if [[ $chars =~ \  ]]; then
                chars=${chars% *}
            else
                chars=
            fi
            hindex=$HISTNO
            find-next
            ;;
        # kill line
        $'\C-u' )
            chars=
            hindex=$HISTNO
            find-next
            ;;
        # add unhandled chars to buffer
        * )
            chars=${chars}${REPLY}
            hindex=$HISTNO
            find-next
            ;;
    esac

    zle -R "${dir}-i-search-multi: $words"
done

これを置くか、あなたからそれを調達してください.zshrc

autoload -U history-incremental-multi-search

# make new widgets from function
zle -N history-incremental-multi-search-backward history-incremental-multi-search
zle -N history-incremental-multi-search-forward history-incremental-multi-search

# bind the widgets to keys
bindkey '^Xr' history-incremental-multi-search-backward
bindkey '^Xs' history-incremental-multi-search-forward

使用する

あなたは今で後方インクリメンタルサーチを開始することができるはずCtrl+Xrと前方に、Ctrl+Xs

スペースで区切って検索キーワードを入力します。次のキーを使用して制御できます。

  • ← Backspace:文字を消去

  • Ctrl+W:単語を消去

  • Ctrl+U:キルライン

  • Ctrl+N: 次の試合

  • Ctrl+P:前の試合

  • Ctrl+G/ Esc:検索をキャンセル

  • Enter:受け入れる

このソリューションは、おそらくかなり簡略化できます。機能の概念実証であり、改善の余地がたくさんあります。


これらの回答を書くために時間を割いていただきありがとうございます、これは私に非常に役立ちます。もっと多くの人がこれに出くわして、役に立つと思います。
drewrobb

6

履歴をgrepできます。

history | egrep '(foo|baz)'

お役に立てば幸いです。


0

@pethの答えを基にして:

Zshにはが付属しhistory-incremental-pattern-search-backwardています。自分で定義する必要はありません。キーバインドを追加するだけです。私^Rは次の行をに追加してオーバーライドすることを好みます.zshrc

bindkey '^R' history-incremental-pattern-search-backward

検索でglob(sic!ではなくrexex)演算子を使用できるようになりました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.