Linux系统良好的文件组织结构,源自类UNIX系统“代代传承”的惯例,但庞大的文件量会引发令人生畏的问题。
系统查找文件的工具:
配合文件查找命令处理结果文件的命令:
locate命令对路径名执行快速的数据库查找,然后输出与给定字符串匹配的各个名称。命令如下:
locate filename #查找包含filename的所有路径
例如:查找包含zip开头的所有程序:
locate bin/zip
输出结果如下:
/usr/bin/zip
/usr/bin/zipcloak
/usr/bin/zipgrep
/usr/bin/zipinfo/usr/bin/zipnote
/usr/bin/zipsplit
如果查找文件比较复杂,可以将locate命令与grep命令等其它与grep等其他命令结合起来。
例如:
locate zip | grep bin
输出结果如下:
/bin/bunzip2
/bin/bzip2
/bin/bzip2recover
/bint/gunzip/
/usr/bin/funzip
/usr/bin/preunzip
locate命令也有几种常用的变体。slocate命令和mlocate命令是现代Linux发行版中常见的两种,不过两者是通过符号链接locate命令访问的。不同的locate有重叠的选项。有些版本支持正则表达式和通配符。
locate命令的数据库是通古updatedb创建的。它通常作为corn作业,有守护进程cron定期执行。大多数locate命令的系统每天执行一次updatedb命令。数据库并不是持续更新的,新创建的文件不会出现查找结果中。可以切换到超级用户执行updatedb命令。
locate命令仅根据文件名查找文件,而find可以根据各种属性在指定目录(及其子目录)查找文件。
find命令较简单的用法就是为其指定一个或多个目录作为查找范围。例如:要想生成文件目录列表,可以这样:
[me@linuxbox ~]$ find ~
find命令可能会生成一个很长的文件列表,统计查找文件到的文件数量:
[me@linuxbox ~]$ find ~ | wc -l
find命令通过各种选项(option)、测试条件(test)以及操作(action)来实现的。
例如查找目录,可以加入下列测试条件:
[me@linuxbox ~]$ find ~ -type d | wc -l
1695
加入测试条件-type d,限制只查找目录。限制只查找普通文件
[me@linuxbox ~]$ find ~ -type f | wc -l
38737
fiind命令支持的常见文件类型
文件类型 | 描述 |
---|---|
b | 块设备文件 |
c | 字符设备文件 |
d | 目录 |
f | 普通文件 |
l | 符号链接 |
还可以加入其它测试条件,安装文件大小和文件名查找。查找所有匹配通配符模式*.JPG且大于1MB的普通文件:
[me@linuxbox ~]$ find ~ -type f -name "*.JPG" -size +1M | wc -l
用于指定计量单位的字符
字符 | 单位 |
---|---|
b | 512B块。这是默认单位(如果未指定单位的话) |
c | B |
w | 字(2B) |
k | KB(Kilobyte, 1024B) |
M | MB(Megabyte, 1048576B) |
G | GB(Gigabyte, 1073741824B) |
先前提到的+和-表示法同样适用。
find命令支持大量测试条件。
常见测试条件
测试条件 | 描述 |
---|---|
-cmin n | 匹配n分钟前内容或属性发生变化的文件或目录。如果不足n分钟,使用-n;如果超过n分钟,就用+n |
-cnewer file | 匹配内容或属性发生变化的时间比file更晚的文件或目录 |
-ctime n | 匹配内容或属性在nx24小时之前发生变化的文件或目录 |
-empty | 匹配空文件或目录 |
-group name | 匹配属于组name的文件或目录。name可以使用组名或者数值形式的组ID来表示 |
-iname pattern | 类似于-name,但是忽略大小写 |
-inum n | 匹配i节点号为n的文件。有助于找出特点i节点的所有硬链接 |
-mmin n | 匹配内容在n分组之前发生变化的文件或目录 |
-mtime n | 匹配内容在nx24小时之前发生变化的文件或目录 |
-name pattern | 匹配符合指定通配符模式pattern的文件或目录 |
-newer file | 匹配内容发生变化的时间比file更晚的文件或目录。在编写执行文件备份的Shell脚本时,该测试条件很有帮助。 |
-nouser | 匹配不属于合法用户的文件或目录。该测试条件可用于查找属于已删除用户的文件或是检测攻击者的活动 |
-nogroup | 匹配不属于合法组的文件或目录 |
-perm mode | 匹配指定权限mode的文件或目录。mode可以使用八进制或符号表示法表示 |
-samefile name | 类似于-inum。匹配i节点号与文件name相同的文件 |
-size n | 匹配大小为n的文件 |
-type c | 匹配类型为c的文件 |
-user name | 匹配属于用户user的文件或目录。name可以使用用户名或数值形式的用户ID表示。 |
完整的列表详见find命令的手册页。
即使有了find命令提供的测试条件,我们可能仍需要体哦国内一种更好的方式来描述测试条件之间的逻辑关系。
例如:查找权限不为0600的文件和权限不为0700的目录,可以使用逻辑操作符组合多个条件,命令如下:
[me@linuxbox ~]$ find ~ \( -type f -not p-erm 0600\) -or \( -type d -not -perm 0700 \)
find命令的操作符
操作符 | 描述 |
---|---|
-and | 如果操作两侧的测试结果均为真,则匹配。该操作符可以简写为-a。注意,如果没有在命令行中写明操作符,则默认假定为-and |
-or | 只要操作符任意一侧的测试结果为真,则匹配。该操作符可以简写为-o |
-not | 只要操作符后的测试结果为假,则匹配。该操作符可以简写为! |
() | 对测试条件和操作符分组,能够形成更大的表达式。该操作符可用于控制逻辑求值的优先级。在默认情况下,find命令的顺序是从左到右。为了获得想要的结果,需要覆盖默认求值书顺序。分组有时候有助于增强命令的可读性。注意,因为括号对Shell具有特殊含义,所以在命令行中使用的时候必须将其引号标注,以便作为find命令的参数。常见做法是使用反斜线来转义符号 |
拆解上面的find命令。从整体看测试条件分为两组,彼此之间由-or分隔:
(expression 1) -or (expression 2)
(file with bad perms) -or (directory with bad perms)
因为正确权限的结果较多,所以要测试"不正确权限"(not good permissions)。对于文件我们将正确权限定义为0600;对于目录,将正确权限定义为0700。测试具有不正确权限的文件表达式如下:
-type f -and -not -perms 0600
测试目录的表达式如下:
-type d -and -not -perms 0700
find ~ (-type f -and -not -perms 0600) -or (-type d -and -not -perms 0700)
操作符有另一个重要的特征。假设有两个被操作符分隔的表达式:
expr1 -operator -expr2
无论哪种情况下,exper1都会被求值;但exper2是否会被求值,就得看操作符了。
工作方式
exper1的结果 | 操作符 | exper2 |
---|---|---|
真 | -and | 总是被求值 |
假 | -and | 不会被求值 |
真 | -or | 不会被求值 |
假 | -or | 会被求值 |
得到find命令的查找结果固然有用,但我们真正想做的是对结果执行某些操作。除了一些与定义好的操作,也可以应用用户的自定义操作。
find命令的预定以操作
操作 | 描述 |
---|---|
-delete | 删除当前匹配的文件 |
-ls | 对匹配文件执行相当于ls-dils命令的操作。输出结果被发送至标准输出 |
将匹配文件的完整路径名输出至标准输出。这是默认操作 | |
-quit | 一旦发现匹配就退出 |
find ~ -type f -name ‘*.bak’ -delete
警告 在使用-delete操作时,一定要小心,在实际删除文件之前,先使用-print代替-delete,确认查找结果无误。
操作符是如何影响操作的。执行下列命令:
find ~ -type f -name '*.bak' -print
该命令查找所有扩展为.bak(-name ‘*.bak’)的普通文件(-type -f),将每个匹配输出到至标准输出(-print)。产生这种结果的原因是测试条件和操作之间的逻辑关系。两者之间的默认关系是-and。也可以更清晰地表达出这种关系:
find -type f -and -name '*.bak' -and -print
操作符如何影响命令执行
测试条件/操作 | 何时执行ls |
---|---|
-type f 为真和-name ‘*。bak’均为真 | |
-name ‘*.bak’ | type -f为真 |
-type f | 总是执行ls,因为它是-and逻辑关系中的第一部分 |
把-print操作放在最前面,命令结果可就大不一样:
find ~ -print -and -type f -and -name '*.bak'
该命令会输出所有文件,然后测试文件和指定的扩展名。
除了预定义操作,还可以针对查找结果调用任意命令。传统实现方式使用-exec操作。其用法如下:
-exec command {};
command命令名。{}代表当前路径名的符号。 ;作为分隔符,表示命令结束。
例如使用-exec操作实现类似于先前讨论过的-delete操作的操作:
-exec rm ‘’{}’ ‘;’
因为{}和;对Shell具有特殊含义,所以必须对其进行标注或转义。
也可以交互是地执行用户自定义操作。只需要使用-ok操作代替-exec操作即可。在执行命令之前会提示用户:
find ~ -type f -name ‘foo*’ -ok ls -l ‘{}’ ‘;’
-rwxr-xr-x 1 me me 224 2007-10-29 18:44 /home/me/bin/foo
< ls … /home/me/foo.txt > ? y
-rw-r–r-- 1 me me 0 2016-09-19 12:53 /home/me/foo.txt
这个例子中,查找名称以foo开头的文件并对找到的每个文件执行命令 ls -l。-ok操作会在执行ls命令之前提示用户。
当使用-exec操作时,每找到一个匹配文件,就会执行指定命令的一个新示例。有时候,血药将所有的查找结果合并在一起,执行单个命名实例。例如,不要像下面执行命令:
ls -l file1
ls -l file2
而是这样:
ls -l file1 file2
这样一来,命令只需要执行一次,而不再执行多次。有两种实现方法:传统方式和现代方式。前者使用外部命令xargs,后者使用find命令自身的一个新特征。
将结尾的分号改成加号,就能让find命令将查找结果组合成参数列表,供指定的命令一次性使用。在之前的例子中,没找到一个匹配文件,就要执行一次ls命令:
find ~ -type f -name ‘foo’ -exec ls -l ‘{}’ ‘;’
-rwxr-xr-x 1 me me 224 2007-10-29 18:44 /home/me/bin/foo
-rw-r–r-- 1 me me 0 2016-09-19 12:53 /home/me/foot.txt
find ~ -type f -name ‘foo’ -exec ls -l ‘{}’ +
-rwxr-xr-x 1 me me 224 2007-10-29 18:44 /home/me/bin/foo
-rw-r–r-- 1 me me 0 2016-09-19 12:53 /home/me/foo.txt
find path -type f -name 'filename' | xargs command #将find命令查找的文件列表执行command操作
xargs命令从标准输入接受输入,将其转换为指定命令的参数列表。我们可以在例子中这样使用:
find ~ -type f -name ‘foo*’ -print | xargs ls -l
-rwxr-xr-x 1 me me 224 2007-10-29 18:44 /home/me/bin/foo
-rw-r–r-- 1 me me 0 2016-09-19 12:53 /home/me/boo.txt
注意 命令参数的数量不是没有限制的。有可能出现命令长度超出Shell接受能力的情况。如果出现了这种情况,xargs命令可以使用系统支持的最大参数数量来执行指定的命令,然后重复此过程,直至处理完所有参数。在执行xargs命令时加入–show-limits选项就能知道系统支持的最大参数数量。
touch名令用于将文件的时间修改为当前系统的时间。
touch filename #将filename的时间修改为当前的系统时间,若filename不存在则创建filename
stat filename #用来查看filename的详细信息
例如:修改playground/timestamp文件的时间
stat playground/timestamp
File: ‘playground/timestamp’
Size: 0 Blocks: 0 IO Block : 4096 regular empty file
Device: 803h/2051d Inode:14265061 Links:1
Access:(0644/-rw-r–r–) Uid:(1001/me) Gid:(1001/me)
Access:2018-10-08 15:15:39 .000000000 -0400
Modify:2018-10-08 15:15:39 .000000000 -0400
Change:2018-10-08 15:15:39 .000000000 -0400
命令输出如下:
File: ‘playground/timestamp’
Size: 0 Blocks: 0 IO Block : 4096 regular empty file
Device: 803h/2051d Inode:14265061 Links:1
Access:(0644/-rw-r–r–) Uid:(1001/me) Gid:(1001/me)
Access:2018-10-08 15:23:33 .000000000 -0400
Modify:2018-10-08 15:23:33 .000000000 -0400
Change:2018-10-08 15:23:33 .000000000 -0400
可以看出文件的最后访问时间,修改时间以及更改时间都变为了15:23:33。
用于控制find命令查找范围的选项。这些选项可以与其它测试条件和操作共同使用。
常用的find命令选项
选项 | 描述 |
---|---|
-depth | 要求find命令在处理目录本身之前先处理该目录中的文件。如果指定了-depth操作,则自动应用此选项 |
-maxdepth levels | 设置find命令在执行测试和操作时,向下1深入的最大目录层级数 |
-mindepth levels | 设置find命令在执行测试和操作之前,向下深入的最小目录层级数 |
-mount | 要求find命令不遍历挂载在其它文件系统上的目录 |
-noleaf | 要求find命令不根据其查找类UNIX文件系统的假设来优化查找。再扫描DOS/Windows文件系统和CD-ROM的时候,需要使用该选项 |