如何在命令行上实现增量(find-as-type-type)搜索?

时间:2010-04-22 11:22:26

标签: scripting

我想编写一些小脚本,它们在命令行上进行增量搜索(find-as-type-type)。

使用案例:我通过USB连接手机,使用gammu --sendsms TEXT我可以写短信。我将电话簿作为CSV,并希望在其上搜索我的类型。

最简单/最好的方法是什么?它可能是在bash / zsh / Perl / Python或任何其他脚本语言中。

编辑: 解决方案:修改Term::Complete做了我想要的。请参阅下面的答案。

2 个答案:

答案 0 :(得分:4)

我得到的印象 GNU Readline 支持这种事情。虽然,我自己没有用过它。 Here is a C++ example自定义自动完成,也可以在C中轻松完成。 readline还有一个Python API

This StackOverflow question在Python中提供了示例,其中一个是......

import readline
def completer(text, state):
    options = [x in addrs where x.startswith(text)]
    if state < options.length:
        return options[state]
    else
        return None
readline.set_completer(completer)
关于Bash自动完成的

this article可能有所帮助。本文还提供了编程bash自动完成功能的示例。

答案 1 :(得分:4)

继艾登贝尔的暗示之后,我在Perl尝试了Readline。 解决方案1使用Term :: Complete(我认为CPAN也使用):

use Term::Complete;   
my $F; 
open($F,"<","bin/phonebook.csv"); 
my @terms = <$F>; chomp(@terms); 
close($F);


my $input;
while (!defined $input) {
   $input = Complete("Enter a name or number: ",@terms);
   my ($name,$number) = split(/\t/,$input);
   print("Sending SMS to $name ($number).\n");
   system("sudo gammu --sendsms TEXT $number");
}

按\完成,按Ctrl-D查看所有可能性。

解决方案2:Ctrl-D是一次击键,因此使用标准的Term :: Readline可以完成并仅使用\来显示可能的完成。

use Term::ReadLine;

my $F;
open($F,"<","bin/phonebook.csv");
my @terms = <$F>; chomp(@terms);
close($F);

my $term = new Term::ReadLine;
$term->Attribs->{completion_function} = sub { return @terms; };

my $prompt = "Enter name or number >> ";

my $OUT = $term->OUT || \*STDOUT;
while ( defined (my $input = $term->readline($prompt)) ) {
   my ($name,$number) = split(/\t/,$input);
   print("Sending SMS to $name ($number).\n");
   system("sudo gammu --sendsms TEXT $number");
}

此解决方案仍需要完成。

编辑:最终解决方案 修改术语::完成(http://search.cpan.org/~jesse/perl-5.12.0/lib/Term/Complete.pm)确实让我即时完成。

源代码:http://search.cpan.org/CPAN/authors/id/J/JE/JESSE/perl-5.12.0.tar.gz 解决方案编号1适用于此修改。如果有人可以使用,我会将整个样本放在其他地方

Completion.pm的修改(只是重复使用Control-D的代码和每个字符的\):

170c172,189

        my $redo=0;

                @match = grep(/^\Q$return/, @cmp_lst);
                unless ($#match < 0) {
                    $l = length($test = shift(@match));
                    foreach $cmp (@match) {
                        until (substr($cmp, 0, $l) eq substr($test, 0, $l)) {
                            $l--;
                        }
                    }
                    print("\a");
                    print($test = substr($test, $r, $l - $r));
                          $redo = $l - $r == 0;
                          if ($redo) { print(join("\r\n", '', grep(/^\Q$return/, @cmp_lst)), "\r\n"); }
                    $r = length($return .= $test);
                }
                    if ($redo) { redo LOOP; } else { last CASE; }

my $redo=0; @match = grep(/^\Q$return/, @cmp_lst); unless ($#match < 0) { $l = length($test = shift(@match)); foreach $cmp (@match) { until (substr($cmp, 0, $l) eq substr($test, 0, $l)) { $l--; } } print("\a"); print($test = substr($test, $r, $l - $r)); $redo = $l - $r == 0; if ($redo) { print(join("\r\n", '', grep(/^\Q$return/, @cmp_lst)), "\r\n"); } $r = length($return .= $test); } if ($redo) { redo LOOP; } else { last CASE; }