2011-04-11 103 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