6 个版本

使用旧的 Rust 2015

0.1.5 2018 年 5 月 6 日
0.1.4 2018 年 4 月 22 日

#1 in #ignore-case

MIT 许可证

23KB
406

findr - 无标志的查找文件

我对 Unix find 命令提供的功能数量印象深刻,但仍然无法记住如何使用它进行除基本功能之外的操作;否则我会去谷歌搜索。我对标志的记忆不是很好,但我确实记得 表达式findr 只接受两个参数;基本目录和一个 过滤表达式

$ findr . 'path.ext=="rs" && path.size > 1kb'
$ findr . 'path.is_file && date.before("1 jan")'
$ findr . 'path.ext=="md" and date.after("last tuesday")'

过滤表达式传递了 pathdatemode,由于功能强大的小嵌入式语言 rhai,因此支持相当任意的表达式。作为一个小便利,"and"、"or" 和 "not" 被理解,因为这些在匆忙中更容易输入。

path 具有以下字段

  • is_file 这个路径是文件吗?
  • is_dir 这个路径是目录吗?
  • is_exec 这个文件可执行吗?
  • is_write 这个路径可写吗?
  • size 文件条目的字节数
  • ext 文件路径的扩展名
  • file_name 路径的文件名部分

还有一个 matches 方法(例如 path.matches("*/readme.*")),以及一个不区分大小写的 ASCII 对应版本 matches_ignore_case

date 具有以下方法

  • before(datestr) 所有在此日期之前修改的文件
  • after(datestr) 所有在此日期之后修改的文件
  • between(datestr,datestr) 所有在这两个日期之间修改的文件
  • on(datestr) 所有在此天修改的文件

mode 只是通常的 Unix 权限位 - 表达式可以包含 Rust 表示法中的八进制常量(例如 0o755

数字可以有一个大小前缀(kb、mb、gb - 不区分大小写)并且日期字符串由 chrono-english 解释。

目前,findr会忽略由.gitignore排除的隐藏目录和文件。没有使用标志的情况下,这并不完全可能!

~$ findr -h
findr: find files and filter with expressions

  -n, --no-hidden look at hidden files and follow hidden dirs
  -g, --no-gitignore do not respect .gitignore
  -f, --follow-links follow symbolic links
  -i, --case-insensitive do case-insensitive glob matches
  -m, --manual show more detailed help about findr

  <base-dir> (path) base directory to start traversal
  <filter-function> (default 'true') filter paths

默认情况下,它使用英式英语日期(即不是“9/11”),除非定义了环境变量FINDR_US

尊重.gitignore可以让你的生活更轻松,如果你对构建工件不感兴趣。在Rust项目中特别有用,因为增量编译会产生大量的中间构建工件。(如果你确实需要覆盖默认设置,则-gn将完成这项工作。)

有了findr,我现在终于可以回答“我在星期二都做了些什么?”这个问题了。

~$ findr . 'date.on("last tues")'
./rust/repos/findr/src/errors.rs
./rust/scratch
./rust/scratch/over/test.over
./rust/scratch/over/type1.over
./rust/scratch/over/over.rs
./rust/scratch/over/empty.over
./rust/scratch/over/tuple.over
./rust/scratch/over/strs.over
./rust/scratch/over/main.over
./rust/scratch/over/id.over
./rust/scratch/over/numbers.over
./rust/scratch/over/strings.over
./rust/scratch/over/map.over
./rust/scratch/over/str.over
./rust/scanlex/src
./rust/scanlex/src/lib.rs

使用-g标志(忽略.gitignore),那天有538个文件被更改!

为了说明我的关于标志狂热的观点,findr . 'path.ext="rs"'的精确等价物是

find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f -name '*.rs' -print

(我不得不查一下)

快捷过滤器

ripgrep默认值启发的功能是快捷过滤器

引用--manual

If a filter is not provided and the base is not a dir, then
it is interpreted as a glob pattern searching from current dir.
If the glob does not start with '*', then:
  *  file-pattern becomes */file-pattern
  * .ext becomes *.ext

也就是说,findr readme.md相当于findr . 'path.matches("*/readme.md"),而findr .c相当于findr . 'path.matches("*.c")

--case-insensitive-i)标志将发出matches_ignore_case而不是matches,因此findr -'readme.*'将匹配README.TXTREADME.md或野外发现的任何许多变体。

此外,我们允许在这个隐含的通配符模式之后添加一个额外的条件。如果是<>,那么它的意义是路径大小表达式,否则是时间表达式。

因此,findr '.c after last tues'将给我所有在最后一个星期二之后修改的C源文件,而findr '.doc > 256Kb'将给出所有大于256Kb的.doc文件。(单引号仍然很重要,以保护我们的表达式不受shell通配符扩展的影响。)

要查看findr对其过滤器所做的转换,设置环境变量FINDR_DEBUG

依赖关系

~9–17MB
~217K SLoC