Linux find基础

搜索文件在使用操作系统中是非常频繁的操作,一个系统中可能有成千上万的文件,怎么快速找到想要的文件是提升效率的关键。Linux中我们可以使用强大的find命令。find命令可以说是Linux中最常用也最复杂的命令,特别是和其他命令一起执行的时候。由于find具有强大的功能,所以它的选项也非常多,其中大部分都值得我们花时间了解一下。

find命令的一般形式

find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]
find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]

上面的find命令可以简化为:

find pathname -options [-print -exec -ok ... action]

命令参数:

pathname: find命令所要查找的目录路径。例如用 . 表示当前目录,用 / 表示根目录

-print: 将find命令匹配到的文件输出到标准输出
-exec: 将find命令匹配到的文件执行该参数指定的shell命令。相应的命令形式为 'command' {};
-ok: 和 -exec 相同,只不过更安全

find命令最简单的使用是,搜索一个或多个目录。

$ find .
.
./.android
./.android/adbkey
./.android/adbkey.pub
./.android/androidwin.cfg
./.android/avd
./.android/cache
./.android/cache/api-versions-6.bin
[...]
$
$ find / 
/
find: /.fseventsd: Permission denied
/.MobileBackups
find: /.MobileBackups: Permission denied
/.OSInstallerMessages
/.PKInstallSandboxManager
/.PKInstallSandboxManager-SystemSoftware
/.vol
/Applications
/Applications/.DS_Store
/Applications/.localized
/Applications/Adobe Application Manager
/Applications/Adobe Photoshop CC 2014
/Applications/Adobe Photoshop CC 2014/Adobe Photoshop CC 2014.app
[...]
$

也可以一次搜索多个目录:

$ find . /
[...] // 输出结果太多,省略

如果仅仅只是列出某个目录的所有文件就感受不到find的强大。find可以通过组合各种选项来组成搜索条件来完成搜索,而且还可以运用各种相关的操作。

测试条件

我们可以根据文件类型来搜索。find支持的文件类型如下(-type 参数):

文件类型 描述
b 块设备文件
c 字符设备文件
d 目录
f 普通文件
l 符号链接

比如我们只想搜索某个目录下面所有的子目录:

$ find . -type d 
.
./.android
./.android/avd
./.android/cache
./.atom
./.atom/.apm
./.atom/.apm/_locks
./.atom/.apm/atom-autocomplete-php
./.atom/.apm/atom-autocomplete-php/0.18.9
./.atom/.apm/atom-autocomplete-php/0.18.9/package
[...]
$

我们也可以只搜索某个目录下的普通文件:

$ find ~ -type f | wc -l
868386
$

也可以根据文件大小来搜索(-size 参数):

字符 单位
b 512个字节块。如果没有指定单位,则这是默认值。
c 字节
w 两个字节的字
k 千字节(1024字节)
M 兆字节(1048576字节)
G 千兆字节(1073741824字节)

我们可以搜索目录下面文件大小大于1G的文件:

$ find ~ -type f -size +1G
/Documents/Virtual Machines.localized/Windows 10 x64 2.vmwarevm/Virtual Disk-s001.vmdk
./Documents/Virtual Machines.localized/Windows 10 x64 2.vmwarevm/Virtual Disk-s002.vmdk
./Documents/Virtual Machines.localized/Windows 10 x64 2.vmwarevm/Virtual Disk-s003.vmdk
[...]
$

上面的例子使用了文件类型和文件大小一起作为搜索的测试条件,只有文件类型是普通文件而且大小大于1G的文件才会被搜索到。我们也可以再增加搜索条件:

$ find ~ -type f -name "*.png" -size +1M | wc -l
5543
$

上面的例子中我们使用了-name测试条件,后面跟通配符模式。注意我们使用双引号括起来,是为了阻止bash展开星号。上面的测试条件是找到文件名以png结尾,并且是普通文件类型的文件,而且文件大小要大于1M。如果在数字参数前面加上+或者-则表示大于或者小于指定数。

find的其他测试条件,下面是一些常见的测试条件,在数值参数的前面可以使用+或者-

测试条件 描述
-cmin n 匹配的文件和目录的内容或属性最后修改时间正好在 n 分钟之前。 指定少于 n 分钟之前,使用 -n,指定多于 n 分钟之前,使用 +n。
-cnewer file 匹配的文件和目录的内容或属性最后修改时间早于那些文件。
-ctime n 匹配的文件和目录的内容和属性最后修改时间在 n*24小时之前。
-empty 匹配空文件和目录。
-group name 匹配的文件和目录属于一个组。组可以用组名或组 ID 来表示。
-iname pattern 就像-name 测试条件,但是不区分大小写。
-inum n 匹配的文件的 inode 号是 n。这对于找到某个特殊 inode 的所有硬链接很有帮助。
-mmin n 匹配的文件或目录的内容被修改于 n 分钟之前。
-mtime n 匹配的文件或目录的内容被修改于 n*24小时之前。
-name pattern 用指定的通配符模式匹配的文件和目录。
-newer file 匹配的文件和目录的内容早于指定的文件。当编写 shell 脚本,做文件备份时,非常有帮助。 每次你制作一个备份,更新文件(比如说日志),然后使用 find 命令来决定自从上次更新,哪一个文件已经更改了。
-nouser 匹配的文件和目录不属于一个有效用户。这可以用来查找 属于删除帐户的文件或监测攻击行为。
-nogroup 匹配的文件和目录不属于一个有效的组。
-perm mode 匹配的文件和目录的权限已经设置为指定的 mode。mode 可以用 八进制或符号表示法。
-samefile name 相似于-inum 测试条件。匹配和文件 name 享有同样 inode 号的文件。
-size n 匹配的文件大小为 n。
-type c 匹配的文件类型是 c。
-user name 匹配的文件或目录属于某个用户。这个用户可以通过用户名或用户 ID 来表示。

操作符

上面的测试条件只是一部分,限于篇幅只能列出笔记常用的。那么这么多测试条件如果都并列写在一起将不便于阅读。所以find提供了逻辑操作符来创建复杂的测试条件,也便于阅读和维护。逻辑操作符如下:

操作符 描述
-and 如果操作符两边的测试条件都是真,则匹配。可以简写为 -a。 注意若没有使用操作符,则默认使用 -and。
-or 若操作符两边的任一个测试条件为真,则匹配。可以简写为 -o。
-not 若操作符后面的测试条件是真,则匹配。可以简写为一个感叹号(!)。
() 把测试条件和操作符组合起来形成更大的表达式。这用来控制逻辑计算的优先级。

注意,find命令从左往右计算,而且要注意圆括号在bash中要转义

我们可以使用上面的逻辑操作符来构造复杂的测试条件,例如只查找特定某些文件:

find . \(-name "*.pdf" -or -name "*.txt"\)

上面的例子会打印当前目录下以.txt.pdf结尾的文件名。也可以找出目录下不是pdf的普通文件:

find . ! -name "*.pdf"

逻辑操作符可以描述为下面的简短形式。逻辑操作符还有一种和其他编程语言相同的特性:短路。下面是逻辑操作符的执行情况:

expr1 -operator expr2

expr1的结果 操作符 expr2的执行情况
-and 总要执行
-and 从不执行
-or 从不执行
-or 总要执行

预定义操作

find除了可以根据特定条件搜索文件外,还可以在搜索到文件之后根据搜索结果执行预定义的操作。find预定义的常用的操作如下表:

操作 描述
-print 把匹配文件的全路径名输送到标准输出。如果没有指定其它操作,这是 默认操作。
-delete 删除匹配到的文件
-ls 对匹配到的结果执行 ls -dils 命令,然后将结果输出到 STDOUT
-quit 一旦找到一个匹配,就退出

find .

会输出当前目录的所有文件和子目录,这相对于:

find . -print

也可以使用-delete来删除搜索到的文件和目录:

find . -empty -delete
find . -type f -name '*.txt' -delete

上面的第一条命令会删除当前目录下的空目录和空文件,第二条命令会删除当前目录下面所有的txt文件。( 好像例子不是太好:( )
当使用-delete时得特别小心,可以先用print输出看看里面有没有不能删除的文件

自定义操作

find除了可以使用预定义的操作之外,还可以通过-exec来自定义操作:

find path [expression] -exec command {} ;

上面的-exec是表示自定义操作的开始,command就是shell命令的名字,{}是当前路径名的符号表示,分号是命令结束的标志。

find . -type f -name "*.zip" -size +100M -exec rm {} \;

删除当前目录下大于100M的压缩文件。上面命令中的{}代表find找到的文件路径,find的结果会放到{}位置之中作为rm的参数。

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

上面的命令用于输出当前目录下所有的pdf文件详情。当使用-exec时,每找到一个匹配就会执行一次-exec后面的命令。有时候我们可能希望将find的结果作为一个整体然后再运行额外的命令,这个时候就可以使用外部命令xargsxargs从标准输入接受输入,并把输入转换为一个特定命令的参数列表,这样命令就不用每匹配到一个文件或目录就执行一次。

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

因为xargs接受标准输入,所以把find的结果用管道(pipe)到xargs的输入,xargs会把输入构造为ls的参数列表,然后执行ls命令。这种方式比-exec方式快很多,ls执行的次数远远小于-exec的匹配到文件就执行一次命令。
xargs后面的命令并不是只执行一次,这取决于输入的参数的个数,如果超过了bash能够处理的最大长度,xargs会使用最大的参数长度执行后面的命令,然后重复这个过程,直到所有的输入都执行完。

你可能感兴趣的:(Linux find基础)