1 Introduction

1.1 Definity

Find–Walk a file hierarchy(层级). 相比其他命令, 其功能非常强大, 其用法也非常繁杂.
Find常常与xargs搭配使用.

1.2 Format

format: find ${start_directory} ${test} ${options} ${criteria to match} ${action to perform on results}

其中:

  • start_directory: 作用根目录
  • test: 检查条件, 当且仅当测试为True时才会进行后续的操作, 否则进行下一个文件的检查, 匹配, 操作
  • options: 参数选项, 例如mtime, 见下文介绍
  • criteria to match: shell匹配表达式
  • action to perform on results: 对结果的操作, 如果搭配xargs使用, 一般不会使用当前项.

除了上述的各个阶段之后, 还存在Operators来连接不同的expression, 其中expression就会包括上面的所有阶段.

关于find, 参考find官网

2 Expression

2.1 test

只有测试成功返回 TRUE 的item 才会进行后续的options, match, action, 下面给出各个test参数. 其中数字参数n有三种
情况:

  • +n 返回项大于n, 例如n天之后
  • -n 返回项小于n, 例如n天之前
  • n 返回项正好与n相等, 例如3天前, 不包括4天前

其他test选项会在下面给出, 仅仅给出一些常见的例子, 其中关于n的语法这里不再说明.

文件访问, 修改时间:

  • amin n: 读取和访问时间, 以分钟为单位, 例外还有(atmin, mtime, ctime, 以天为单位)
  • mmin n: 上次内容修改时间
  • cmin n: 上次状态更改时间
  • newer file: 比文件file还近的更改时间
  • empty: 空文件
  • executable: 可执行文件

文件所有者:

  • user: 基于用户名查找
  • group: 基于组名查找
  • uid: 基于UID查找
  • gid: 基于GID查找
  • nouser: 基于没有属主查找
  • nogoup: 基于无属组查找

文件名:

  • name: 匹配模式, 使用shell模式进行匹配
  • iname: 不分大小写
  • lname: 对软链接文件进行模式匹配
  • ilname: 不区分大小写
  • links n: 对硬链接文件
  • regex: 基于正则表达式
  • iregex: 匹配模式

文件类型:

  • type: 基于文件类型查找(f/d/b/c/l/s/p)
  • size: 【+|-】SIZE 单位: b-512, c-bytes, w-two bytes, k-Kib, M-Mib, G-Gib
  • context pattern: 文本包含

路径查找:

  • path pattern: 注意, 这是一个pattern, 即对find命令前面部分的结果的一种正则匹配, 这一点非常重要
  • perm: MODE 基于精确权限查找
  • perm: /MODE 任何一位匹配即可
  • perm: -MODE 同时符合,与关系

所以, 在使用-path选项时, 第一部分路径需要和后续path的正则匹配, 否则永远找不到想要的文件:

1
2
3
4
5
6
7
8
# True
find . -path "./bamboo_*"
# False
find ./ -path "./bamboo_*"
# 至于原因, 可以查看``find ./``输出就会了解

# 忽略指定的文件, 这是path的常用方式, 此时会忽略所有bamboo_开头的文件
find ./ -path "./bamboo_*" -prune

2.2 Options

Positions OptionsGlobal Options 一直返回True, 其仅仅会影响经过test过滤之后的数据.

关于软链接文件:

  • -L: 输出软连接文件实际的文件, 而不是连接文件本身
  • -P: 默认行为, 不会输出实际软链接文件
  • -H: 当需要对每一个文件进行单独的处理时, 此时需要操作软链接本身文件

Global Options:

  • -d/–depth: 深度优先排序算法查找
  • maxdepth levels: 最大深度
  • mindepth levels: 最小深度, 例如使用mindepth来忽略根目录本身
  • mount: 不操作其他文件系统的文件

2.3 Actions

  • delete: 对于返回到这一步的所有文件, 直接进行删除操作, 一步到位, 够男人
  • exec command ; : 对所有的文件逐一执行命令, 返回0表示命令执行成功, 其中参数由exec到;之间的值组成, 另外会使用\来转义;
  • execdir command; : 对包含文件的目录执行
  • print0: 输出到stdout
  • fprint file: 将输出全部打印到file中
  • fprintf file format: 以指定格式打印文件
  • ls: 以ls -dils打印到stdout中
  • fls /PATH/TO/SOMEFILE 将查找到的文件已ls -l格式保存到文件中
  • ok COMMAND {} \; 查找到的文件传递给命令COMMAND,每一步都需要提示确认

2.4 Operators

  • ( expr ): 优先执行
  • ! expr : 当且仅当expr返回False时, 可以使用-not来替代
  • expr1 expr2: 两个条件都必须生效, 类似: expr1 -a expr2, 如果前面失败, 后面的表达式就不会执行
  • expr1 -a expr2, expr1 -and expr2: 并条件
  • expr1 -o expr2, expr1 -or expr2: 或条件
  • expr1, expr2: 不管如何, 两个expr都会执行完毕

关于expression的组合:

1
2
3
# 默认为-and,其他还有(!expr, -not expr, -a/-and/-o/-or/)
!A and !B = !(A or B)
!A or !B = !(A and B)

3 Example

在cscope中, 使用-L 来遍历链接文件(实际文件):

1
2
# 查看所有的.h, .c, cpp, java, py, php文件并放到cscope库中, 以便后续的查找
find -L `pwd` -name "*.h" -o -name "*.c" -o -name "*.cpp" -o -name "*.java" -o -name "*.py" -o -name "*.php" >cscope.files

按照文件大小查找

1
2
3
4
5
6
7
# 例如大于5MB
find / -size +5000000c 2 > /dev/null
# 对大小为0的文件进行操作, 直接删除
find test -type f -size 0 -delete

# 查获空文件
find . -empty

多选项查找

1
2
3
4
5
# 查找当前目录下所有的以.c, .h结尾的所有文件
find ./ -name "*.c" -o -name "*.h"

查找非指定格式的所有文件, 使用-not, -name来筛选:
find ./ -type f -not -name "*.c" -not -name "*.h" -not -name "Makefile" -not -name "makefile" -not -name "*.png"

按照文件权限和所有者进行查找

1
2
3
4
5
# 普通, 777文件
find . -type f -perm a=rwx -exec ls -l {} \;
find . -type f -perm 777 -exec ls -l {} \;
# 查找user, group都能读写的文件
find . -type f -perm /ug=rw -exec ls -l {} \;

设置忽略根目录, 并设置最大搜索深度

1
2
# mindepth 默认为0
find /user/ -maxdepth 3 -mindepth 1