Skip to content

Better fnmatch(), supporting `**` like `.gitignore`, in Rust

License

Notifications You must be signed in to change notification settings

hamstergene/pathmatch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pathmatch: a better fnmatch

This is an experiment to develop an improved alternative to POSIX fnmatch function. It can be used, for example, when implementing .gitignore-like functionality.

The module interface is currently a single global function, without extra options:

pub fn pathmatch(pattern: &str, pathstring: &str) -> bool

Note: this implementation does not exactly match actual .gitignore and contains more functionality (e.g. {} patterns).

A quick taste of the idea

*.txt matches file names without path, if they end with “.txt”:

one.txt
two.txt

**.txt matches any path ending with “.txt”:

one.txt
two.txt
foo/3.txt
foo/bar/4.txt

**/build/** would match any path containing “build” folder anywhere in it, including the bare string build itself.

**/build/{Debug,Release} matches paths whose two last folders are either build/Debug or build/Release:

build/Debug
build/Release
subproject1/build/Debug
subproject1/build/Release

In other words, **/ may match start of the path string, /** may match end of the path string, and /**/ may match single path separator (/). To disable this behavior, explicitly require something to be present before/after: */**/build/{Debug,Release}, */**/build/**/*.

The ? wildcard is also supported, matching exactly one character excluding path separator.

pmfind command line tool

You can use the included pmfind tool to test pathmatch() in real world:

  $ ./pmfind '{*.rs,Makefile}' '**/{logs,master}'
pmfind.rs
pathmatch.rs
Makefile
.git/refs/remotes/origin/master
.git/refs/heads/master
.git/logs
.git/logs/refs/remotes/origin/master
.git/logs/refs/heads/master

Usage:

Usage:
        ./pmfind [options] [pattern ...]

Options:
    -C --dir dir        change directory to this before starting
    -h --help           print help and exit

If a pattern starts with !, pmfind excludes paths matching it from output, otherwise those paths are printed. Patterns are applied in the order they appear on the command line, so the latest match decides whether the path will be printed. Paths that match no patterns are never printed. Example:

  $ ./pmfind '**/master'
.git/refs/remotes/origin/master
.git/refs/heads/master
.git/logs/refs/remotes/origin/master
.git/logs/refs/heads/master

  $ ./pmfind '**/master' '!**/logs/**'
.git/refs/remotes/origin/master
.git/refs/heads/master

  $ ./pmfind '**/master' '!**/logs/**' '**/logs/refs/heads/master'
.git/refs/remotes/origin/master
.git/refs/heads/master
.git/logs/refs/heads/master

About

Better fnmatch(), supporting `**` like `.gitignore`, in Rust

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages