поиск по файлу в стиле bash reverse-search-history - PullRequest
2 голосов
/ 11 апреля 2011

Я пытаюсь написать функцию, которая будет искать файл таким же образом, как работает история обратного поиска.т. е. пользователь начинает вводить, приглашение обновляется при первом совпадении, нажатие на специальную клавишу вращается через другие совпадения, нажатие на другую специальную клавишу выбирает текущее совпадение.

Я написал сценарий bash для этого, но это ужасно медленно.Интересно, смогу ли я использовать какую-нибудь другую функцию Unix / Bash, чтобы сделать это быстро.Может быть, с использованием awk?

Любые идеи приветствуются.

Для этого скрипта TAB вращается через совпадения, ENTER выбирает текущее совпадение, ESC завершается, BACKSPACE удаляет последнееперсонаж в текущем поиске.(простите за мой хитрый сценарий bash, я относительно новичок в bash / unix)

#!/bin/bash


do_search()
{
        #Record the current screen position
        tput sc
        local searchTerm
        local matchNumber=1
        local totalSearchString
        local TAB_CHAR=`echo -e "\t"`

        #print initial prompt
        echo -n "(search) '':"

        #-s: means input will not be echoed to screen, -n1 means that one character will be gotten
        while IFS= read -r -s -n1 char
        do
                #If ENTER
                if [ "$char" == "" ]; then
                        if [ "$match" != "" ]; then
                                eval "$match"
                        fi
                        echo ""
                        return 0

                #If BACKSPACE
                elif [ "$char" == "" ]; then
                        if [ "$totalSearchString" != "" ]; then
                                totalSearchString=${totalSearchString%?}
                        fi

                #If ESCAPE
                elif [ "$char" == "" ]; then
                        tput el1
                        tput rc
                        return 0

                #If TAB
                elif [ "$char" == "$TAB_CHAR" ]; then
                        matchNumber=$(($matchNumber+1))

                #OTHERWISE
                else
                        totalSearchString="$totalSearchString$char"
                fi

                match=""
                if [ "$totalSearchString" != "" ]; then
                        #This builds up a list of grep statements piping into each other for each word in the totalSearchString
                        #e.g. totalSearchString="blah" will output "| grep blah"
                        #e.g. totalSearchString="blah1 blah2" will output "| grep blah1 | grep blah2"
                        local grepStatements=`echo $totalSearchString | sed 's/\([^ ]*\) */| grep \1 /g'`
                        local cdHistorySearchStatement="cat $1 $grepStatements | head -$matchNumber | tail -1"

                        #Get the match
                        match=`eval "$cdHistorySearchStatement"`
                fi

                #clear the current line
                tput el1
                tput rc

                #re-print prompt & match
                echo -n "(search) '$totalSearchString': $match"
        done
  return 0
}

do_search categories.txt

Ответы [ 2 ]

1 голос
/ 11 апреля 2011

Я не думаю, что это можно сделать достаточно быстро для интерактивного использования в чистом bash (может быть, с помощью встроенного complete?).Тем не менее, вы можете попробовать упростить команды, которые вы используете.Вместо одного grep на слово вы можете использовать один для всех, выполнив

  grepStatements=$(echo "$totalSearchString" | sed 's/[ ]\+/|/g')
  cdHistorySearchStatement="grep '$grepStatements' $1 | ..."

и вместо head -$matchNumber | tail -1 вы можете использовать sed -n ${matchNumber}{p;q}.

1 голос
/ 11 апреля 2011

Я думаю, что для этого bash использует readline, почему бы вам не использовать его самостоятельно?Я не знаю об этом больше, извините, но я подумал, что это может помочь.

...