文章目录

一、locate–较简单的方式查找文件

​locate​​​命令通过快速搜索数据库,以寻找路径名与给定的子字符串相匹配的文件,同时输出所有匹配结果。例如,假定查找名称以zip字符串开头的程序,由于查找的是程序文件,所以可以认为包含所要查找的程序的路径名应以bin/结尾。
因此,可以尝试下面的命令行。

[wangjichuan@mr-jarvis ~]$ locate

​locate​​程序将搜索该路径名数据库,并输出文件名包含字符串bin/zip的所有文件。

Linux--文件搜索_命令行


有时搜索需求并不是这么简单,这时便可以用​​locate​​​命令结合其他诸如​​grep​​这样的工具实现一些更有趣的搜索。

Linux--文件搜索_命令行_02


​locate​​​程序已经使用了很长时间,因此出现了多种衍生体。​​slocate​​​和​​mlocate​​​是现代Linux发行版本中最常见的两个衍生体,而它们通常都是由名为locate的符号链接访问的。不同版本的​​locate​​​有一些相同的选项设置,而有些版本则包括正则表达式匹配和通配符支持等。我们可以查看​​locate​​​的​​man​​​手册页确定系统安装的是哪个版本的​​locate​​。

二、find–较复杂的方式查找文件

​locate​​​程序查找文件仅仅是依据文件名,而​​find​​​程序则是依据文件的各种属性在既定的目录(及其子目录)里查找。
​​​find​​​最简单的用法就算用户给定一个或是更多个目录名作为其搜索范围。下面就用​​find​​命令列出当前系统主目录(~)下的文件列表清单。

[wangjichuan@mr-jarvis ~]$ find

对于一些比较活跃的用户,一般系统内文件会比较多,使得上诉命令行输出的列表肯定很长。不过,列表信息是以标准形式输出的,所以可以直接将此输出结果作为其他程序的输入。如下就是用​​wc​​​程序计算​​find​​命令搜索到的文件的总量。

Linux--文件搜索_find命令_03


​find​​命令的美妙之处就是可以用来搜索符合特定要求的文件,它通过综合应用test选项、action选项以及option选项实现高级文件搜索。

2.1、test选项

假定我们想要查找的是目录文件,我们可以添加下面的test选项达到此目的。

[wangjichuan@mr-jarvis ~]$ find ~  -type  d  |  wc

添加test参数​​-type d​​​可以将搜索范围限制为目录,而下面的例子中使用​​-type f​​则表示只对普通文件进行搜索。

[wangjichuan@mr-jarvis ~]$ find ~  -type  f  |  wc

find支持搜索的文件类型

文件类型

描述

b

块设备文件

c

字符设备文件

d

目录

f

普通文件

l

符号链接

另外我们还可以添加其他的test选项参数实现依据文件大小和文件名的搜索。如下命令行就是用来查找所有符合*.JPG通配符格式以及大小超过1MB的普通文件。

[wangjichuan@mr-jarvis ~]$ find ~  -type  f   -name  "*.JPG"  -size  +1M  |  wc

本例中添加的​​-name "*.JPG"​​​的test选项表示查找的是符合.JPG通配符格式的文件。注意,这里将通配符扩在双引号中是为了避免shell路径名扩展。另外ia添加的​​-size +1M​​的test选项,前面的加号表示查找的文件大小比给定的数值1M大。若字符串前面是减号则代表要比给定数值小,没有符号则表示与给定值完全相等。为末的M是计量单位MB(兆字节)的简写,下表列出了每个字母与特定计量单位之间的对应关系。

find支持的计量单位

字母

单位

b

512字节的块(没有具体说明时的默认值)

c

字节

w

两个字节的字

k

KB(每单位包含1024字节)

M

MB(每单位包含1048576字节)

G

GB(每单位包含1073741824字节)

​find​​命令支持多种test参数,下表概括了一些常见的参数。

find命令的test参数

test参数

描述

-cmin n

匹配n分钟前改变状态(内容或属性)的文件或目录。如果不到n分钟,就用-n,如果超过n分钟,就用+n

-cnewer file

匹配内容或属性的修改时间比文件file更晚的文件或目录

-ctime n

匹配系统中n*24小时前文件状态被改变(内容、属性、访问权限等)的文件或目录

-empty

匹配空文件及空目录

-group name

匹配属于name组的文件或目录。name可以描述为组名,也可以描述为该组的ID号

-iname pattern

与-name test项功能类似只是不区分大小写

-inum n

匹配索引节点是n的文件,该test选项有助于查找某个特定索引节点上的所有硬件连接

-mmin n

匹配n分钟前内容被修改的文件或目录

-mtime n

匹配n*24小时前只有内容被更改的文件或目录

-name pattern

匹配由特定通配符模式的文件或目录

-newer file

匹配内容的修改时间比file文件更近的文件或目录。这在编写shell脚本进行文件备份的时候非常有用。每次创建备份时,更新某个文件(比如日志),然后用find+此参数选项来确定上一次更新后哪个文件改变了

-nouser

匹配不属于有效用户的文件或目录。该test可以用来查找那些属于已删除账户的文件,也可以用来检测攻击者的活动

-nogroup

匹配不属于有效组的文件或目录

-perm mode

寻找访问权限与既定模式匹配的文件或目录。既定模式可以以八进制或符号的形似表示

-samefile name

与-inum test选项类似。匹配与file文件用相同的inode号的文件

-size n

匹配n大小的文件

-type

匹配c类型的文件

-user name

匹配属于name用户的文件和目录。name可以描述为用户名也可以描述为该组的ID号

注意:前面所讲述的“+”和“-”号的用法适用于所有用到数值参数的情况

操作符
即使拥有了​​​find​​​命令提供的所有test参数,我们仍然会需要一个更好的工具来描述test参数之间的逻辑关系。例如,如果我们需要确定某目录下是否所有的文件和子目录都有安全的访问权限,该怎么办?原则上就是去查找那些访问权限不是0600的文件和访问权限不是0700的子目录。幸运的时,​​find​​​命令的test选项可以结合逻辑操作从而建立具有复杂逻辑关系的匹配条件。我们可以用下面的命令行来满足上述​​find​​命令的匹配搜索。

[wangjichuan@mr-jarvis ~]$ find ~  \( -type f -not -perm 0600 \) -or \(  -type d -not -perm 0700  \)

find命令的逻辑操作符

操作符

功能描述

-and

查找使该操作符两边的检验条件都是i真的匹配文件。有时直接缩写成-a。注意如果两个检测条件之间没有显示的显示操作符,and就是默认的逻辑关系

-or

查找使该操作符任何一边的检测条件为真的匹配文件。有时直接缩写成-o

-not

查找使该操作符后面的检测条件为假的匹配文件。有时直接缩写成-!

()

多个检测条件和逻辑操作符一起组成更长的表达式,而()操作符就是用来区分逻辑表达式优先权的。默认的情况下,find命令从左向右运算逻辑值。然而有时为了获得想要的结果必须扰乱默认的执行顺序,即便不需要,将一串字符表达式扩起来对提高命令的可读性也很有帮助。请注意,括号字符在shell环境中有特殊意义,所以必须将它们在命令行中用引号引起来,这样此阿能作为find的参数传递,通常用反斜杠来避免这样的问题

2.2、action选项

前面的​​find​​​命令已经查找到所需要的文件,但是我们真正想做的是处理已查找到的文件。幸运的是,​​find​​命令允许直接对搜索结果执行动作。

预定义动作

对搜索到的文件进行操作,既可以用诸多现成的预定义动作指令,也可以使用用户自定义的动作。首先来看一些预定义动作:

预定义的find命令操作

动作

功能描述

-delete

删除匹配文件

-ls

对匹配文件执行ls操作,以标准格式输出其文件名以及所要求的其他信息

-print

将匹配的文件的全路径以标准形式输出。当没有指定任何具体操作时,该操作是默认操作

-quit

一旦匹配成功便退出

与test参数选项相比,actions参数选项数量更多,可以参考find的man手册页获取更全面的信息。
​​​find ~​​​,此命令产生了一个包含当前系统主(~)目录中所有文件和子目录的列表。该列表之所以会在屏幕上显示,是因为在没有指定其他操作的情况下,-print操作是默认的。因此,​​find ~​​​与​​find ~ -print​​​是等效的。
当然也可以使用​​​find​​命令删除满足特定条件的文件。示例如下,此命令行用于删除.BAK(这种文件一般是用来指定备份文件的)后缀的文件。

[wangjichuan@mr-jarvis ~]$ find   ~   -type   f    -name   '*.BAK'

本例中,用户主目录及其子目录下的每个文件都被搜索了一遍匹配文件名以.BAK结尾的文件。一旦被找到,则直接删除。

注意:毫无疑问,使用-delete操作时一定要格外小心,最好先用-print操作确认搜索结果后再执行-delete删除命令

[wangjichuan@mr-jarvis ~]$ find   ~   -type   f    -name   '*.BAK'

上述命令用来查找所有文件名以.BAK结尾的普通文件(-type f)并且以标准形式(-print)输出每个匹配文件的相关路径名。然而,该命令行之所以照这样的方式执行是由每个test选项和action选项之间的逻辑关系决定的。记住,每个test选项和action选项之间默认的逻辑关系是与(and)逻辑。下面的命令行逻辑关系能更清楚地体现这一点:

[wangjichuan@mr-jarvis ~]$ find   ~   -type   f    -name   '*.BAK'

test选项与action选项之间逻辑关系决定了它们的执行情况,所以test选项和action选项的顺序很重要。例如,如果重新排列这些test选项和action选项,并将​​-print​​操作作为逻辑运算的第一个操作数,那么命令行的运行结果将会有很大的不同。

[wangjichuan@mr-jarvis ~]$ find   ~   -print   -type   f     -and    -name   '*.BAK'

此命令行会把每个文件显示出来(因为-print操作运算符总是为真),然后在对文件类型以及特定的文件扩展名进行匹配检查。

用户自定义操作

除了已有的预定义操作命令,同样也可以任意调用用户想要操作的操作命令。传统的方法就是像以下命令行使用-exec操作。

-exec command {}

该格式中的command表示要执行的操作命令名,{}花括号代表的是当前路径,而分号作为必需的分隔符表示命令结束。使用​​-exec​​​完成​​-delete​​操作示例如下:

-exec  rm  '{}'  ';'

同样,由于括号和分号字符在shell环境下有特殊含义,所以在输入命令行时,要将它们用引号引起来或者使用转义符隔开。

当然,交互式地执行用户自定义操作也不是不可能。通过使用-ok操作取代原来的​​-exec​​操作,每一次指定命令执行之前系统都会询问用户。

Linux--文件搜索_搜索_04


上例中,查找文件名以b字符开始的文件,并且每次找到匹配文件后执行​​ls -l​​​命令。​​-ok​​操作会在ls命令执行之前询问用户是否执行。

提高效率

当使用​​-exec​​操作时,每次查找到匹配文件后都会调用执行一次指定命令。但有时用户更希望只调用一次命令就完成对所有文件的操作。例如,多数人可能更喜欢这样的命令执行方式。

ls  -l  file1
ls

而不是以下这样的方式:

ls

第一种方式只需要执行命令一次,而第二种方式则要多次重复执行。实现这样的一次操作有两种方法:一种方式比较传统,使用为外部命令​​xargs​​​;另一种则是使用​​find​​本身自带的新特性。首先介绍下第二种方法。

find   ~   -type   f   -name   'foo*'   -exec   ls  -l   '{}'   ';'

每次找到匹配文件后就执行一次​​ls​​命令。将上述命令行改为下面的命令行。

find   ~   -type   f   -name   'foo*'   -exec   ls  -l   '{}'

我们也能得到相同的结果,但是系统整体只执行一次​​ls​​命令

同样我们可以使用​​xargs​​​命令获得相同的效果,​​xargs​​​处理标准输入信息并将其转变为某指定命令的输入参数列表。结合前面的实例,我们可以这样使用​​xargs​​命令。

find   ~   -type   f   -name   'foo*'   -print   |   xargs   ls

该命令行中,find命令的执行结果直接作为​​xargs​​​输入,xargs反过来将其转换成了​​ls​​​命令的输入参数列表,最后执行​​ls​​操作。

注意:虽然一个命令行中可允许输入的参数有很多,但这并不表示可以无限输入,也存在命令行过长而使得shell编辑器无法承受的情况。如果命令行中包含的输入参数太多而超过了系统支持的最大长度,xargs只会尽可能对最大数量的参数执行指定操作,并不断重复这一过程直到所有标准输入全部处理完毕。在xargs命令后面添加–show-limits选项,即可直到命令行最大能承受的参数数量。

2.3、返回到playground文件夹

现在可以实际应用 ​​find​​命令了。首先让我们创建一个包含很多子目录及文件的playground文件夹平台。

[wangjichuan@mr-jarvis ~]$ mkdir -p playground/dir-{00{1..9},0{10..99},100}
[wangjichuan@mr-jarvis ~]$ touch playground/dir-{00{1..9},0{10..99},100}/file-{A..Z}

我们使用上述命令创建了一个包含100个子目录的playground文件夹,并且每个子目录中又包含26个空文件。

我们创造这个奇迹的方法包含了一个熟悉命令​​mkdir​​​、一个奇异的shell花括号扩展以及一个新命令​​touch​​​。​​mkdir​​命令结合-p选项(-p选项使mkdir命令按指定的路径创建父目录)的同时用花括号扩展,便完成了100个目录的创建。

​touch​​命令一般用于设定或是更新文件的修改时间。然而,当文件名参数是一个不存在的文件时,那么该命令就会创建一个空文件。

playground文件夹里,总共创建了100个较多file-A的文件。现在,我们可以查找它们。

Linux--文件搜索_搜索_05

注意:与​​ls​​​命令不同,​​find​​命令不会产生有排列顺序的结果,其输出顺序是由在存储设备中的布局决定的。

下面来看一个根据文件的修改时间查找文件的例子,这在创建备份文件以及按时间顺序排列文件是非常有用。首先需要创建一个用作比较时间的参照文件。

[wangjichuan@mr-jarvis ~]$ touch

该命令行创建了一个名为timestamp的空文件,并将当前时刻设为该文件的修改时间。我们可以使用另外一个便捷的命令​​stat​​​来检验执行效果,​​stat​​​命令可以说是​​ls​​的增强版,该命令会将系统所掌握文件的所有信息及属性全部显示出来。

Linux--文件搜索_命令行_06


当我们再一次对此文件执行​​touch​​​命令并用​​stat​​命令检验时,会发现文件的时间得到了更新。

Linux--文件搜索_find命令_07


接下来,我们便可以使用​​find​​命令更新playground文件夹里的一些文件。

[wangjichuan@mr-jarvis ~]$ find    plauground   -type   f   -name   'file-B'   -exec   touch   '{}'   ';'

上述命令更新了playground文件夹里面叫做file-B的所有文件。下面我们通过比较参照文件timestamp与其他文件的修改时间,使用​​find​​命令查找刚刚被更新的文件。

[wangjichuan@mr-jarvis ~]$ find

命令行的运行结果包含100个文件名为file-B的文件。由于我们是在对timestamp文件执行了​​touch​​​命令之后,才对playground文件夹和宗对名为file-B的所有文件执行力touch操作,所以它们现在要比timestamp文件新,从而我们可选用​​-newer​​ test选项来查找。

2.4、option选项

option选项用于控制​​find​​​命令的搜索范围。在构成​​find​​命令的表达式时,它们可能包含在其他测试选项或行为选项之中。下表列出了最常用的option选项:

find命令的option选项

选项

描述

-depth

引导find程序处理目录前先处理目录内文件。当指定-delete操作时,该参数选项会自动调用

-maxdepth levels

当执行测试条件行为时,设置find程序陷入目录数的最大级别数

-mindepth levels

当应用测试条件行为之前,设置find程序陷入目录数的最小级别数

-mount

引导find不去遍历挂载在其他文件系统上的目录

-noleaf

指导find程序不要基于“正在搜索类UNIX文件系统”的假设来优化它的搜索。当扫描DOS/Windows文件系统和CD时,会用到该选项