dgaramond2 has asked for the wisdom of the Perl Monks concerning the following question:

I want to provide the users of my command-line script a way to select some objects based on one or more criteria. I figure that the syntax for Unix's find is ideal as most of them are already familiar with it. Examples:

# select all stones % stone.pl % stone.pl '*' # select only stones whose names match a wildcard % stone.pl 'p*' # blue stones starting with p % stone.pl 'p*' -color blue # blue or green stones % stone.pl 'p*' -color blue -o -color green # discard stones tagged as expensive and not tagged as valuable % stone.pl -tag +expensive -and -tag -valuable -discard

For converting wildcard to Perl's regex, there's File::KGlob2RE. The hard part for me is implementing the multiple criteria syntax: 'expr -and -expr', 'expr -or expr', '( expr )' and '-not expr'.

Pointers would be appreciated. Hopefully there's something on CPAN I can use as a base.

Replies are listed 'Best First'.
Re: How to implement something similar to Unix's find syntax?
by leocharre (Priest) on May 25, 2007 at 10:00 UTC

    File::Find::Rule might be of interest to you. If your 'objects' were YAML files, for example.. Well. You can imagine from there. It could be slow loading those.

    The other option is a database. MySQL is fast at select queries and slow on inserts, as compared to sqlite, driver for DBI, which is slow at selects and fast on inserts. In my experience (doing millions of small inserts very quickly).

    If you want to use a database I would suggest go with sqlite, if you use the cpan DBI driver, it's self contained- that is- you just install that. No need for a server daemon ( like with mysql)- later if you want- you can change to mysql without messing your code too much.

    It could help to be more specific.. objects? OO, or .. an abstract idea of "objects"?

      as compared to sqlite, driver for DBI, which is slow at selects and fast on inserts
      WTF. That's not what other people have reported. (Though it probably can be faster at inserts if you do it properly.)
      The objects are ordinary Perl objects (well, unblessed hashes, actually, and yes they are loaded from YAML files). But the objects are not the issue. As others have guessed, I am (or will be used to, hopefully) absolutely clueless in parsers and compilers.
Re: How to implement something similar to Unix's find syntax?
by jettero (Monsignor) on May 25, 2007 at 11:01 UTC

    I'm not sure find's argument syntax is something you'd want to intentionally replicate, unless it was actually identical. I can make find do some fantastic things, but it's not the most intuitive thing in the world.

    Anyway, if you want ordinary find in perl, try find2perl ./ -type f | perl?

    What I think would be really neat would be a DBD::AnyData interface for File::Find so you could do SQL queries against your filesystem. I'd use that a lot I bet.

    -Paul

Re: How to implement something similar to Unix's find syntax?
by merlyn (Sage) on May 25, 2007 at 18:07 UTC
Re: How to implement something similar to Unix's find syntax?
by moritz (Cardinal) on May 25, 2007 at 10:06 UTC
    I'd suggest to write a very simple recursive descending parser, that should be easy without exceeding 30 simple lines.

    If you have absolutely no clue about it, read the first two chapters of Let's Build a Compiler, it's no deep magic at all. Perhaps Parse::RecDescent can help you with that

    P.S does anybody know a more up to date but equally simple introduction to parsers and compilers?

Re: How to implement something similar to Unix's find syntax?
by sanPerl (Friar) on May 25, 2007 at 12:29 UTC
    I am just trying to create a funny code. It accepts two arguments directory to search and filename
    It will work on Unix. you can make it work on Windows by reversing the slash.
    Just try perl <script name> <dir name> <file name>
    my ($mydir, $word) = (@ARGV); opendir(DIR, "$mydir") || warn "can't opendir : $!"; @dots = grep { /\w/ } readdir(DIR); closedir DIR; foreach $dir_tree(@dots) { #print "$dir_tree\n"; opendir(DIR, "$dir_tree"); @dots1 = grep { /\w/ } readdir(DIR); foreach $dir_tree1(@dots1) { push @dots, "$dir_tree/$dir_tree1"; my $name = "$dir_tree/$dir_tree1"; print "$dir_tree/$dir_tree1\n" if ($name =~ m/\Q$word\ +E/is); } closedir DIR; }
      I think the original intention was to implement a parser for options similar to find.

      If I understand the original posting correctly, it has nothing to do with actually finding files, but to apply that logic to a completely different problem.