find用法汇总

去年猪厂内推机试中看到了关于find命令的考题,find命令还是很常用的,但无奈用法太丰富,一直记得不全,索性趁假日休息,汇总一下。

本文是4月的开胃小菜,也是第一次写命令的使用,有不恰之处,望指正。

命令格式

find [path] [expr]

path表示搜索的根路径,绝对路径和相对路径均可。expr则用于条件搜索,可以指定约束条件。

按文件名搜索

如果需要搜索指定形式的文件,例如所有txt文件,我们可以使用-name选项指定文件名,这里可以接受通配符匹配,由于包含特殊字符,所以最好使用双引号括起来。

例:搜索所有png文件

find / -name "*.png"
# 忽略大小写
find / -iname "*.png"

如果需要将文件地完整路径作为匹配的对象,则可以使用-path

例:搜索img目录下的png文件

find / -path "*/img/*.png"
# 忽略大小写
find / -ipath "*/img/*.png"

如果想要使用更加精确的正则表达式,则可以通过-regex选项进行匹配,它和-path的类似,目标都是路径。

例:搜索png或jpg文件

find / -regex ".*\(\.jpg | \w+\.png\)$"
# 忽略大小写
find / -iregex ".*\(\.jpg | \w+\.png\)$"

按时间查找

Linux有3种类型的时间戳,分别是访问时间、修改时间和变化时间,相关细节不再复述。find支持根据指定的时间戳类型搜索对应时间范围内的文件。

find支持如下时间戳相关的参数:

  • -atime:访问时间(单位:天)
  • -mtime:修改时间(单位:天)
  • -ctime:变化时间(单位:天)
  • -amin:访问时间(单位:分)
  • -mmin:修改时间(单位:分)
  • -cmin:变化时间(单位:分)

这些参数对应的值有如下形式:

  • -N:小于N
  • N:等于N
  • +N:大于N

例:搜索2天内修改过的txt文件

find . -mtime -2 -name "*.txt"

按文件大小查找

通过-size参数可以指定期望文件的大小,具体值的形式和上一节类似,除此之外,支持的单位如下:

  • b:块(512B)
  • c:字节(1B)
  • w:字(2B)
  • k:1024B
  • M:1024KB
  • G:1024MB

例:搜索全部大小在20KB之内的C源文件

find . -size -20k -name "*.c"

按文件类型查找

通过-type参数可以确定待查找文件的文件类型,这个的类型和test中的类型缩写是一样的,如下是一个简单列表:

  • f:普通文件
  • l:符号链接
  • d:目录
  • c:字符设备
  • b:块设备
  • s:套接字
  • p:管道

例:搜索/var目录下的所有套接字

find /var -type s

按权限查找

通过-perm参数,我们可以在表达式内部制定目标文件的权限,该参数的值具备3种类型。

为了更好地说明,不妨令参数制定的权限位P,目标文件的权限位T,则

  • P:精确匹配,P == T
  • -N:子集关系,(P & T) == T
  • /N:任何一个权限位匹配即可,(P & T) != 0

例:搜索当前用户可以修改的C源文件

find . -type f -perm -0600 -name "*.c"

除了8进制的权限值,也可使用o=w之类的形式。

根据用户/组查找

通过-user-group,可以限定期望文件的所属用户与组。

例:搜索所有属于users组的png文件

find / -type f -group users -name "*.png"

搜索深度

当文件量巨大时,搜索将变得十分耗时,如果你已经知道文件的深度,则可以通过如下参数进行约束:

  • -mindepth:对不小于该深度的路径应用表达式
  • -maxdepth:对不大于该深度的路径应用表达式

例:搜索深度不大于3的目录中的所有png文件

find . -type f -maxdepth 3 -name "*.png"

表达式

上述的约束其实均为表达式的一个子式,find支持括号notorand,默认情况下所有的子式均采用and的形式组成。

  • ( expr )
  • ! expr 亦可使用-not expr,不遵循POSIX
  • expr -a expr 亦可使用expr -and expr,不遵循POSIX
  • expr -o expr 亦可使用expr -or expr,不遵循POSIX
  • expr , expr

逻辑表达式是支持短路的,可以做适当优化。

例:寻找所有png或jpg文件

find / -type f \( -name "*.png" -o -name "*.jpg" \)

表达式优化

和SQL一样,语义相同的find表达式,其执行效率可能完全不同。

一些建议:

  1. depth参数应该紧跟path,效果就如同“先做JOIN再select”和“先select再JOIN”
  2. type在depth之后
  3. type之后才是常见的约束项

其他

  1. 分隔符

find与xargs命令结合使用,通常会需要使用-print0,它指定'\0'作为分隔符。默认情况下,搜索的结果使用'\n'或者' '作为分隔符,此时如果文件名中包含空格,会就出现误操作的情况,因此需要指定一个名字中不可能出现的字符作为分隔符,最好的选择自然就是'\0'了(当然不会是'/',这样的问题更大)。

  1. 执行指令

对于搜索结果我们可以通过增加额外的指令来执行对其进行的操作,默认的操作为-print,即打印其路径。

除此之外,常见的还有-delete-exec,前者的作用很明显,而后者则可执行自己定制的命令,如下:

例:将所有png文件转移到backup目录

find / -type f -name "*.png" -exec cp {} backup \;

其中{}表示文件名,;则表示命令结束,-exec只支持单条指令。

  1. 略过特定目录

如果我们需要在搜索时略过特定目录,可以使用-prune

例:打印除.config目录以外的所有文件路径

find . \( -name ".config" --prune \) -o \( -type f -print \) 

-delete-prune不能同时出现在表达式内,因为前者默认开启了-depth-depth参数指明先处理目录的内容后处理目录本身,与-prune冲突。

说两句: