tìm kiếm lịch sử ngược với các biểu thức thông thường


10

Tôi đang tìm kiếm một công cụ để cho phép tìm kiếm gia tăng ngược với sự hỗ trợ biểu thức chính quy đơn giản (hoặc chỉ nhiều kết quả khớp). Ví dụ: nếu tôi muốn tìm lệnh 'foo bar baz', tôi có thể làm một cái gì đó như sau để tìm lệnh nhanh chóng:

CRTL-R (bắt đầu tìm kiếm) gõ 'foo' (khớp với lệnh gần đây nhất bằng foo) tiếp tục nhập 'foo | baz' (khớp với lệnh gần đây nhất chứa 'foo' AND 'baz'.

Có một cái gì đó như thế này tồn tại? Nếu không, làm thế nào tôi có thể tự mình thực hiện nó?

Câu trả lời:


4

Tiện ích tùy chỉnh history-incremental-multi-searchchozsh

Thiết lập

Tạo một thư mục và đưa nó vào $fpathví dụ của bạn , tôi đã tạo một thư mục ~/.zsh/functionsvà dòng fpath=($HOME/.zsh/functions $fpath)trong của tôi .zshrc.

Đặt sau đây trong một tập tin có tên history-incremental-multi-searchtrong thư mục đó.

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

Đặt cái này vào hoặc lấy nó từ .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

Sử dụng

Bây giờ bạn có thể bắt đầu một tìm kiếm gia tăng ngược với Ctrl+X, r, về phía trước với Ctrl+X, s.

Nhập cụm từ tìm kiếm của bạn được phân tách bằng dấu cách. Các phím sau có sẵn để kiểm soát nó:

  • ← Backspace: xóa nhân vật

  • Ctrl+W: xóa từ

  • Ctrl+U: dòng giết

  • Ctrl+N: trận đấu tiếp theo

  • Ctrl+P: trận đấu trước

  • Ctrl+G/ Esc: hủy tìm kiếm

  • Enter: Chấp nhận

Giải pháp này có thể được đơn giản hóa khá nhiều. Đó là một bằng chứng chức năng của khái niệm, với rất nhiều chỗ để cải thiện.


Cảm ơn bạn đã dành thời gian để viết những câu trả lời này, điều này giúp tôi rất nhiều. Tôi hy vọng nhiều người vấp phải điều này và thấy nó hữu ích.
drewrobb

6

Bạn có thể grep qua lịch sử của bạn:

history | egrep '(foo|baz)'

Tôi hy vọng điều đó sẽ giúp.


0

Xây dựng câu trả lời của @ peth:

Bây giờ Zsh đi kèm history-incremental-pattern-search-backward, bạn không cần phải tự xác định nó. Chỉ cần thêm ràng buộc chính. Tôi thích ghi đè ^Rbằng cách thêm dòng sau vào .zshrc:

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

Bây giờ bạn có thể sử dụng toán tử toàn cầu (sic! Not rexex) trong tìm kiếm của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.