find 命令用于在 Linux 命令行中搜索文件和目录。

find 是功能最强大、使用最频繁的命令之一,同时也是选项最多的命令之一,它有50多个选项,很容易让人弄混了,特别是当它与 exec 或 xargs 命令一起使用的时候。

作为系统管理员或者软件开发者,在命令行中工作时都不可避免的会使用到 find 命令。所以,与其畏难而逃避它,不如知难而进,拥抱它的力量。

本文我们会分享关于 find 命令的一些常见示例。不过在此之前,我们先来看一下它的语法,以及如何使用。


Linux 中的 find 命令

find 命令的一般语法为:

find [directory to search] [options] [expression]


方括号 [] 中所有的内容都是可选的,这意味着你可以在没有任何选项和参数的情况下运行 find 命令。不过这只会打印出当前路径下所有的文件和目录,这样没什么用处,对吧?

我们来详细了解一下它的参数。

  • directory to search:要搜索的目录,基本上就是我们要开始搜索的位置。默认情况下,搜索是递归的(也会搜索子目录),从当前位置开始;
  • options:选项,指定搜索的类型,可以按文件名称、文件类型、修改时间等(进行搜索),这里有50多个选项;
  • expression:指定的搜索词。如果是要按文件名查找,那么搜索词就是文件名;如果是要查找名称与表达式匹配的文件,那这里就用表达式。


看下面的例子:

find . -type f -name myfile


该命令将在当前目录及其子目录中进行搜索,查找名为 myfile 的文件(不是目录)。选项 -type f 表示只查找文件,单点 . 表示当前目录。


按名称查找文件和目录

可以按文件名搜索文件和目录:

find . -name SEARCH_NAME


由于没有指定文件类型,所以它会搜索具有给定名称的文件和目录。

下面的例子找到名为 mystuff 的文件和目录:

[gliu@fedora work]$ find -name mystuff
./new/mystuff
./mystuff


只查找文件或目录

如果只想查找文件,那么需要指定文件类型 -f

find . -type f -name SEARCH_NAME


类型和名称的顺序无关紧要。上一个例子中,只查找文件,可使用如下命令:

[gliu@fedora work]$ find -type f -name mystuff
./mystuff


如果只搜索目录,那么指定类型 -d

find . -type d -name SEARCH_NAME


还是上面那个例子,如果只查找目录,使用如下命令:

[gliu@fedora work]$ find -type d -name mystuff
./new/mystuff


执行不区分大小写的搜索

默认情况下,find 命令区分大小写。如果我们想要执行不区分大小写的搜索,可以使用 -iname 来代替 -name

find . -type f -iname SEARCH_NAME


也可以将其与 -d 选项一起使用。

[gliu@fedora work]$ find -iname mystuff
./new/mystuff
./MyStuff
./mystuff


按扩展名搜索(重要)

find 命令最常见的用法之一就是查找指定类型的文件,或者说是按照文件扩展名来进行查找。

比如,我们要在当前目录下搜索所有的 C++ 文件,而C++文件的扩展名是 .cpp,所以我们可以这样搜索:

find . -type f -name "*.cpp"


这样,我们告诉 find 命令查找类型为文件(file),并且以 .cpp 结尾的文件。

[gliu@fedora work]$ find . -type f -name "*.cpp"
./file.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream2/zstream_test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/zfstream.cpp


注意:在使用 find 命令时,需要将表达式放在双引号中。

为什么要将表达式放在双引号中呢?因为如果要不这样做的话,shell会扩展通配符,将其替换为当前目录中所有以 .cpp 结尾的文件。

比如,假如当前目录下有两个文件:file1.cpp, file2.cpp,那么下面的命令:

find . -type f -name *.cpp

会被shell扩展为:

find . -type f -name file1.cpp file2.cpp

这种情况下,shell 就会给出提示:

find: paths must precede expression: 'file1.cpp'
find: possible unquoted pattern after predicate '-name'?

另外,如果当前目录下只有一个扩展名为.cpp的文件,那就可以。


搜索多个扩展名(或条件)的多个文件

上述命令搜索给定扩展名的文件。那如果要同时搜索不同扩展名的文件,该怎么办呢?

可以使用逻辑或(OR) -o 来运行 find 命令:

find . -type f -name "*.cpp" -o -name "*.txt"


这样,就会搜索扩展名为 .cpp 或 .txt 的文件:

[gliu@fedora work]$ find . -type f -name "*.txt" -o -name "*.cpp"
./new.txt
./file.cpp
./new/new.txt
./new/dir2/another.txt
./new/dir1/new.txt
./another.txt


在指定目录中查找文件

我们上面的例子都是在当前目录中搜索,因为我们在命令中指定了 . 作为当前路径。

点 . 可以替换为绝对路径或者相对路径。这样我们就可以在不离开当前路径的情况下,在指定的目录中查找文件。

[gliu@fedora work]$ find ./new -name mystuff 
./new/mystuff


在多个目录中搜索文件

如果你认为所要查找的文件可能位于多个位置,那么不必多次运行 find 命令,只需在 find 命令中指定要搜索的所有目录路径即可:

find ./location1 /second/location -type f -name "pattern"


查找空文件和目录

-empty 选项可以让你使用 find 命令查找空文件和目录。比如要查找当前路径下所有的空文件和目录,可使用如下命令:

find . -empty


也可以指定搜索的文件类型,只查找文件或者目录:

find . -empty -type f


还可以结合文件名使用:

find . -empty -type f -name "*.cpp"


查找大文件或小文件(根据文件大小搜索)

根据文件的大小执行搜索,可以查找大文件或者小文件。但这只适用于文件,不适用于目录。

要根据文件的大小搜索,可以使用 -size 选项,后面跟上一个值N(即文件的大小),+N 查找大于 N 的文件,-N 查找小于 N 的文件

比如,查找大小正好为 50KB 的文件:

find . -size 50k


在当前路径下查找大于 1G 的文件:

find . -size +1G


查找小于 20 bytes 的文件(注意单位是c而不是b):

find . -size -20c


要查找大于100 MB 但小于 2 GB 的文件:

find . -size +100M -size -2G


此外,还可以结合名称搜索。比如,要在根目录中查找以 .log 结尾,大于500MB的文件,可使用如下命令:

find / -size +500M -name "*.log"


关于文件大小值 N 的单位:

  • c : bytes(字节)
  • k: kilobytes(千字节)
  • M: Megabytes(兆字节)
  • G: Gigabytes(GB)


查找最近修改的文件(根据修改或创建时间搜索)

我们先来简单介绍下mtimeatime 和 ctime 的概念:

  • mtime:文件上次修改的时间;
  • ctime:文件创建的时间;
  • atime:文件上次访问的时间。


我们经常会有查找最近修改过的文件的需求,这时候,可以按修改时间来搜索文件。

比如,要查找 3天(3 * 24H)以内修改过的所有文件:

find . -type f -mtime -3


再比如,查找 5天以前创建的文件:

find . -type f -ctime +5


上述命令是以天为单位。那么,如果要搜索几分钟前修改过的文件呢?可以使用 mminamin 和 cmin

比如,要查找 5分钟以内修改过的文件,可使用如下命令:

find . -type f -mmin -5


此外,还可以结合名称,指定时间的上限和下限进行搜索。比如,下面的命令将搜索过去20分钟到30分钟内,修改过的所有 .java 文件:

find . -type f -mmin +20 -mmin -30 -name "*.java"


查找具有特定文件权限的文件

find命令允许您搜索具有特定权限的文件。

find -perm mode


比如,在当前路径下查找所有权限模式为 777 的文件:

find . -perm 777


查找具有读写权限的文件(完全匹配,如果文件权限为 读写和执行,则不匹配):

find . -perm a=r+w


根据文件的所属用户查找

find 还可以根据文件的所有权进行搜索。

比如,在当前路径下搜索用户 John 所拥有的文件:

find . -type f -user John


当然,也可以与其他选项(比如文件大小,时间,名称等)结合使用:

find . -type f -user John -name "*.cpp"


不递归查找,仅在当前目录中搜索

默认情况下,find 命令在当前位置的所有子目录中搜索。如果不希望这样,可以将搜索深度指定为 1。这将限制搜索仅限于当前目录,不包括任何子目录。

find . -maxdepth 1 -type f -name "*.txt"

关于 find 命令的15个超级有用的例子_查找文件

从搜索中排除目录

如果要将某个目录从搜索中排除,可以结合 -path-prune 和 -o 一起使用:

find . -path "./directory_exclude/*" -prune -o -name SEARCH_NAME


注意路径中的星号 *-prune 选项在路径之后,-o 选项在 prune 之后。

基本上,prune命令要求不使用路径指定的值,它总是与 -o 一起使用,以确保 -o 的右侧只针对未被排除的目录。


处理 find 命令的输出结果(使用 exec 和 xargs)

到目前为止,我们介绍了关于find命令的一些标准查找文件的方法。此外,还可以通过对 find 命令的结果执行某些操作,来改进它。

例如,查找与特定名称模式匹配的文件并一次性重命名,或者查找空文件并删除。

我们知道,管道重定向可以用于将一个命令的输出与另一个命令输入相结合。但这对find命令的输出不起作用,至少不直接起作用。

如果要对find命令的结果执行操作,有两个选项,即 exec 和 xargs


使用 find 和 exec

假如我们要对 find 的结果使用 ls -l 列出来,看下面的例子:

find . -type f -name "*.txt" -exec ls -l {} +


以下是输出:

[gliu@fedora work]$ find . -type f -name "*.txt" -exec ls -l {} +
-rw-rw-r-- 1 gliu gliu 39 Oct 13 19:30 ./another.txt
-rw-rw-r-- 1 gliu gliu 35 Oct 13 15:36 ./new/dir1/new.txt
-rw-rw-r-- 1 gliu gliu 35 Oct 13 15:36 ./new/dir2/another.txt
-rw-rw-r-- 1 gliu gliu 35 Oct 13 18:51 ./new/mystuff/new.txt
-rwxrwxrwx 1 gliu gliu 35 Oct 13 15:37 ./new/new.txt
-rw-rw-r-- 1 gliu gliu 35 Oct 13 18:16 ./new.txt


不要忘记 exec 命令最后的 {} +,并且要注意 {} 和 之间的空格。

花括号 {} 引用 find 命令的结果,你可以将其认为是 {file1, file2, file3}。加号 + 用于终止 exec 命令。

exec 还有另一个约定:

find . -type f -name *.txt" -exec ls -l {} \;


上述命令中,分号 ; 用于代替加号 +,分号前面的反斜杠 \ 用于转义特殊字符。

{} + 的优点是它运行的命令更少,它就相当于是 ls -l file1 file2 file3;而 {} \ 则相当于运行 ls -l file1, ls -l file2, ls -l file3

但是,{} \;具有在同一 exec 语句中多次使用 {} 的优点。例如,下面的命令将使用 .old 扩展名重命名所有找到的文件:

find . -type f -name *.txt" -exec mv {} {}.old \;


使用 xargs

许多 Linux 用户已经习惯了管道重定向。这个带有尾随 { }+ 的 exec 命令对他们来说似乎不太习惯。

这就是 xargs 命令存在的价值,你只需要通过管道将 find 命令的输出解析到 xargs 命令:

find . -type f -name *.txt" | xargs ls -l

关于 find 命令的15个超级有用的例子_查找文件_02

find 结合 grep 使用

上面我们介绍了 find 结合 exec 和 xargs 命令的使用,此外,还可以将 find 与 grep 命令一块使用。

对于任何系统管理员或软件开发人员来说,find 和 grep 是最常见且最有用的组合之一。

你可以使用 find 命令来查找文件,然后使用 grep 命令来搜索这些文件的内容。

比如,我们要搜索所有包含 “Alice”一词的 txt 文件,那么可以这样搜索:

find . -type f -name "*.txt" -exec grep -i alice {} +


同样的,也可以使用 xargs 命令:

find . -type f -name "*.txt" | xargs grep -i alice

关于 find 命令的15个超级有用的例子_当前目录_03

当然,这是最简单的例子,如果你熟悉 grep 命令,可以根据自己的需求和喜好使用它。