2011-04-11 102 views
2

我正在嘗試編寫一個函數,它將以與反向搜索歷史記錄相同的方式搜索文件。即用戶開始輸入,提示更新爲第一次比賽,擊中特殊鍵旋轉其他比賽,擊中另一個特殊鍵選擇當前比賽。在bash反向搜索歷史文件中搜索文件

我爲此寫了一個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 

回答

1

我覺得Bash使用的ReadLine這個,你爲什麼不考慮自己使用呢?我對此不甚瞭解,抱歉,但我認爲這可能會有所幫助。

+0

readline命令來自(鼓卷)... EMACS。所以你的bash腳本應該只包含像'emacs -nw $ 1' ;-) – flolo 2011-04-12 08:07:53

+0

是的,readline通常用於你正在嘗試做的事情。例如,對於sybase命令(參見http://www.sqsh.org),請參閱sqsh shell,它將比emacs(我認爲)更小,更易於理解。 Sqsh是一個已編譯的'C'程序,鏈接到readline c庫以提供歷史導航。也許有一個獨立的readline,你可以在shell中使用?祝你好運! – shellter 2011-04-12 12:59:07

+0

我已經看過readline。不知道這是否真的是我以後。我可以看到你如何編寫自定義完成器,但是a)我並不熱衷於使用C語言進行編程,b)完成(如顯示可能性列表)並不是我所追求的。如果我誤解了readline的功能,請糾正我。 – Ben 2011-04-13 07:33:11

1

我不認爲這可以做得足夠快,在純bash中使用交互式使用(也許使用內建的complete?)。也就是說,你可以嘗試簡化你正在使用的命令。相反,每一個字grep,你可以使用一個爲所有這些,通過做

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

和替代head -$matchNumber | tail -1你可以使用sed -n ${matchNumber}{p;q}

+0

非常感謝您的意見,我今晚在我的代碼中嘗試您的建議。 – Ben 2011-04-11 21:49:17