概述
参考文档:
三者定位不同:
find按条件遍历目录树,fd是更快更好用的文件名查找,rg专攻文件内容搜索find来自findutils,fd与rg是Rust编写的第三方工具,主流发行版仓库都有包选择路径:
flowchart LR A{"找什么"} -->|"文件名"| B{"条件复杂?"} B -->|"简单"| C["fd"] B -->|"size/mtime/perm 组合"| D["find"] A -->|"文件内容"| E["rg"]
快速开始
$ fd "\.md$" # 按正则找文件名,自动忽略隐藏与 ignore 文件
$ rg "TODO" # 递归搜内容,自动忽略 .gitignore
$ find . -name "*.log" -mtime +7 # 找 7 天前修改过的日志
find
语法是
find 路径... 表达式,路径必须写在表达式前面,不给路径默认当前目录,不给表达式默认-print按名字:
-name "*.c"通配符匹配,-iname忽略大小写,-regex对整个路径做正则按类型与大小:
-type f/d/l,-size +10M大于、-10k小于按时间:
-mtime -7表示7天内修改过,+7表示7天前,-mmin按分钟,-newer file比某文件新按属性:
-user root、-group g、-perm -u+s包含 setuid 位深度:
-maxdepth 2限制遍历层数,属于全局选项,要放在测试类表达式之前组合逻辑:默认
-a与,-o或,!非,\( \)分组:console$ find . \( -name "*.tmp" -o -name "*.swp" \) -type f动作:
-print0以\0分隔输出,文件名可能含空格或换行时必须配xargs -0:console$ find . -name "*.log" -print0 | xargs -0 rm-exec 命令 {} \;每个文件执行一次,{} +尽量合并成一次调用,批量场景更快-delete直接删除,注意它也是普通表达式,位置放错会删错范围
陷阱:一旦表达式里出现了显式
-print或-exec,隐式的整包-print就没了,find . -name a -o -name b -print只会打印匹配b的文件,要两侧都打印得加括号
fd
默认对文件名做正则匹配,智能大小写:模式全小写则忽略大小写,含大写字母则精确匹配
常用选项:
-e md按扩展名过滤,可叠加:-e c -e h-H包含隐藏文件,-I无视.gitignore,默认跳过这两类与.git目录-t f/d/l/x按类型:文件、目录、符号链接、可执行文件-S +1m按大小,--changed-within 1week按修改时间-E node_modules额外排除某目录,-d 2限制深度
找到后执行命令:
-x逐个执行,-X汇总成一次调用,占位符控制路径形式:console$ fd -e jpg -x convert {} {.}.webp # {} 完整路径,{.} 去掉扩展名 $ fd -e log -X rm # 等价 xargs 的汇总模式- 其它占位符:
{/}仅文件名、{//}仅目录、{/.}去扩展名的文件名
- 其它占位符:
与
find的取舍:日常找名字用fd,需要-perm、复杂时间组合或老系统没有fd时回find
rg
默认递归搜当前目录、跳过隐藏与
.gitignore命中的文件,所以裸命令就够用基本形态:
rg 模式 [路径...],模式是Rust正则,默认不支持反向引用,-P启用 PCRE2大小写:智能匹配是默认行为,全小写模式自动忽略大小写,
-s关闭,-S强制开启,-w按整词匹配过滤范围:
-t py只搜某语言,-T js排除某语言,--type-list列出全部别名-g "*.toml"按 glob 包含,-g "!*.lock"排除--hidden搜隐藏文件,--no-ignore无视 ignore 文件,-z连压缩包一起搜
输出控制:
-l只列命中文件,-c每文件计数,-o只输出匹配部分-A 3、-B 3、-C 3显示匹配之后、之前、两侧的上下文行-e a -e b多模式取或,-F按字面量匹配不解析正则
替换与结构化:
-r只替换显示内容不动文件,--json输出机器可读结果,--vimgrep输出编辑器 quickfix 格式管道用法,从 stdin 逐行过滤:
console$ ps aux | rg nginx $ rg -l "TODO" | wc -l # 统计有多少文件含 TODO
相关阅读
- coreutils 入门:找到之后的文件操作
- sed、awk 与进阶 coreutils:找到之后如何批量子处理