정규식을 사용한 역 히스토리 검색


10

간단한 정규 표현식 (또는 여러 개의 일치 항목)을 지원하는 역 증분 검색을 허용하는 도구를 찾고 있습니다. 예를 들어 'foo bar baz'명령을 찾으려면 다음과 같이 명령을 빠르게 찾을 수 있습니다.

CRTL-R (검색 시작) 유형 'foo'(foo를 사용한 가장 최근 명령과 일치) 'foo | baz'( 'foo'AND 'baz'를 포함하는 가장 최근 명령과 일치)를 계속 입력합니다.

이와 같은 것이 존재합니까? 그렇지 않다면 어떻게 직접 구현할 수 있습니까?

답변:


4

사용자 정의 위젯 history-incremental-multi-search을위한zsh

설정

디렉토리를 작성하여 디렉토리에 포함하십시오. $fpath예를 들어, 디렉토리를 작성하고 my ~/.zsh/functionsfpath=($HOME/.zsh/functions $fpath)을 작성하십시오 .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+X, r앞으로와를 Ctrl+X, s.

검색어를 공백으로 구분하여 입력하십시오. 다음 키를 사용하여 제어 할 수 있습니다.

  • ← 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 (exex가 아닌 sic!) 연산자를 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.