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)
查找最近修改的文件(根据修改或创建时间搜索)
我们先来简单介绍下mtime, atime 和 ctime 的概念:
- mtime:文件上次修改的时间;
- ctime:文件创建的时间;
- atime:文件上次访问的时间。
我们经常会有查找最近修改过的文件的需求,这时候,可以按修改时间来搜索文件。
比如,要查找 3天(3 * 24H)以内修改过的所有文件:
find . -type f -mtime -3
再比如,查找 5天以前创建的文件:
find . -type f -ctime +5
上述命令是以天为单位。那么,如果要搜索几分钟前修改过的文件呢?可以使用 mmin, amin 和 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”
从搜索中排除目录
如果要将某个目录从搜索中排除,可以结合 -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 结合 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
当然,这是最简单的例子,如果你熟悉 grep 命令,可以根据自己的需求和喜好使用它。