Linux操作:文件搜索
已经学习Linux这么长时间了,相信大家有一点已经很清楚,就是Linux系统含有非常多的文件!这就自然产生一个问题,“我们应该怎样查找东西?”。虽然我们已经知道,Linux文件系统良好的组织结构,源自于类UNIX的操作系统代代传承的习俗,但是仅文件数量就会引起可怕的问题。 本章我们主要介绍两个用于在Linux系统中搜索文件的工具。 同时,我们也会介绍一个通常与文件搜索命令一起使用、处理搜索结果文件列表的命令。 此外,我们还介绍了两个辅助工具。 1locate——较简单的方式查找文件 locate命令通过快速搜索数据库,以寻找路径名与给定子字符串相匹配的文件,同时输出所有匹配结果。例如,假定查找名称以zip字符串开头的程序,由于查找的是程序文件,所以可以认为包含所要查找的程序的目录名应以bin/结尾。因此,可以尝试下面的命令行。 locate程序将搜索该路径名数据库,并输出文件名包含字符串bin/zip的所有文件。 有时搜索需求并不是这么简单,这时便可以用locate命令结合其他诸如grep这样的工具实现一些更有趣的搜索。 你也许曾注意过,有些Linux版本,系统刚刚安装好时locate命令并不能工作,但是如果第二天再尝试,就会发现它又能正常工作,这到底是怎么回事呢?其实,是因为locate的搜索数据库由另外一个叫做updatedb的程序创建,通常该程序作为一个cron任务定期执行。所谓cron任务就是指定期由cron守护进程执行的任务,多数装有locate命令的系统每天执行一次updatedb命令。由此可见,locate的搜索数据库并不是持续更新的,所以locate命令查找不到非常新的文件。解决方法就是切换为超级用户,在提示框下手动运行updatedb程序。 2find——较复杂的方式查找文件 locate程序查找文件仅仅是依据文件名,而find程序则是依据文件的各种属性在既定的目录(及其子目录)里查找。本章将会花大量的篇幅介绍find命令的用法,因为它有很多有趣的特性会在后面有关编程概念的章节中多次讲到。 find最简单的用法就是用户给定一个或是更多目录名作为其搜索范围。下面就用find命令列出当前系统主目录(~)下的文件列表清单。 [me@linuxbox ~]$find ~ 对于一些比较活跃的用户,一般系统内文件会比较多,使得上述命令行输出的列表肯定很长。不过,列表信息是以标准形式输出的,所以可以直接将此输出结果作为其他程序的输入。如下就是用wc程序计算find命令搜索到的文件的总量。 [me@linuxbox ~]$find ~ | wc -l 47068 find命令的美妙之处就是可以用来搜索符合特定要求的文件,它通过综合应用test选项、action选项以及options选项(看起来有点奇怪)实现高级文件搜索。下面让我们首先了解test选项。 假定我们想要查找的是目录文件,我们可以添加下面的test选项达到此目的。 [me@linuxbox ~]$find ~ -type d | wc -l 1695 添加test参数-type d可以将搜索范围限制为目录,而下面例子中使用-type f则表示只对普通文件进行搜索。 [me@linuxbox ~]$find ~ -type f | wc -l 38737 表17-1列出了find命令支持的常用文件类型。 另外我们还可以通过添加其他的test项参数实现依据文件大小和文件名的搜索。如下命令行就是用来查找所有符合*.JPG通配符格式以及大小超过1MB的普通文件。 [me@linuxbox ~]$find ~ -type f -name "*.JPG" -size +1M | wc -l 8 本例中添加的-name "*.JPG"的test选项表示查找的是符合.JPG通配符格式的文件。注意,这里将通配符扩在双引号中是为了避免shell路径名扩展。另外添加的-size +1M test选项,前面的加号表示查找的文件大小比给定的数值1M大。若字符串前面是减号则代表要比给定数值小,没有符号则表示与给定值完全相等。末尾的M是计量单位MB(兆字节)的简写,表17-2中列出了每个字母与特定计量单位之间的对应关系。 表17-2find支持的计量单位 find命令支持多种test参数,表17-3概括了一些常见的参数。注意,前面所讲述的“+”和“-”号的用法适用于所有用到数值参数的情况。 表17-3find命令的test项参数 即使拥有了find命令提供的所有test参数,我们仍然会需要一个更好的工具来描述test参数之间的逻辑关系。例如,如果我们需要确定某目录下是否所有的文件和子目录都有安全的访问权限,该怎么办?原则上就是去查找那些访问权限不是0600的文件和访问权限不是0700的子目录。幸运的是,find命令的test选项可以结合逻辑操作从而建立具有复杂逻辑关系的匹配条件。我们可以用下面的命令行来满足上述find命令的匹配搜索。 [me@linuxbox ~]$find ~ \( -type f -not -perm 0600 \) -or \( -type d -not -perm 0700 \) 对照这张逻辑操作符的列表,重新剖析上述的find命令行。从最全局的角度看,所有检测条件由一个或(or)操作符分成了两组。 (表达式1)-or(表达式2) 这样做是有原因的,因为我们查找的是具有某种权限设置的文件和另外一种权限设置的目录。那既然要同时查找文件和目录,怎么不是用and而是用or?因为find命令在浏览扫描所有的文件和目录时,会判断每一个文件或目录是否匹配该test项检测条件。而我们的目标是具有不安全访问权限的文件或是具有不安全访问权限的目录,都知道匹配者不可能既该test项检测条件。而我们的目标是具有不安全访问权限的文件或是具有不安全访问权限的目录,都知道匹配者不可能既是文件又是目录,所以不能用and逻辑关系。由此,可将表达式扩充如下。 (file with bad perms) -or (directory with bad perms) 接下来的问题就是如何判断文件或是目录具有“危险”权限,我们该怎么做呢?事实上,我们并不需要直接去寻找“危险”权限的文件或是目录,而是查找那些具有“‘不’好”权限的文件或目录,因为我们知道什么是“好的权限”。对于文件来说,权限是0600表示“好”(安全)的,而对于目录,“好”的权限应该是0700。于是,判断具有“不好”访问权限的文件的表达式如下。 -type f -and -not -perms 0600 同样,判断具有“不好”访问权限的目录的表达式如下。 -type d -and -not -perms 0700 正如表17-4中提到的,and操作是默认的,所以可以安全地移除。把如上表达式都整理到一起以下。 find ~ (-type f -not -perms 0600) -or (-type d -not -perms 0700) 然而,由于括号在shell环境下有特殊含义,所以我们必须对它们进行转义以防shell试图编译它们。在每个括号前加上反斜杠便可解决此问题。 逻辑运算符的另外一个特性也很值得大家了解,有如下两个被逻辑操作符分开的表达式。 expr1 -operatorexpr2 在任何情况下,表达式expr1都会被执行,而中间的操作符将决定表达式expr2是否被执行。表17-5列出了具体执行情况。 表17-5列出了具体执行情况 为什么会出现这样的情况?主要还是为了提高效率,以-and逻辑运算为例,很明显表达式expr1 -and expr2的值在expr1为假的情况下不可能为真,所以就没有必要再去运算表达式expr2了。同样,对于表达式expr1 -or expr2,在表达式expr1为真的情况下其逻辑值显然为真,于是就没有必要再运算表达式expr2了。 由此达到效率提高的目的。但为什么这一性质这么重要?这是因为这将直接影响下一步actions选项的动作行为,下面就来介绍actions选项。 前面find命令已经查找到所需要的文件,但是我们真正想做的是处理这些已查找到的文件。幸运的是,find命令允许直接对搜索结果执行动作。 预定义动作 对搜索到的文件进行操作,即可以用诸多现成的预定义动作指令,也可以使用用户自定义的动作。首先来看一些预定义动作,见表17-6。 表17-6预定义的find命令操作 与test参数选项相比unix系统文件,actions参数选项数量更多,可以参考find的man手册页获取更全面信息。 本章开头所举的第一个例子如下。 find ~ 此命令行产生了一个包含当前系统主(~)目录中所有文件和子目录的列表。该列表之所以会在屏幕上显示出来,是因为在没有指定其他操作的情况下,-print操作是默认的。因此,上述命令行等效于如下形式的命令行。 find ~ -print 当然也可以使用find命令删除满足特定条件的文件。示例如下,此命令行用于删除.BAK(这种文件一般是用来指定备份文件的)后缀的文件。 find ~ -type f -name '*.BAK' -delete 本例中,用户主目录及其子目录下的每个文件都被搜索了一遍匹配文件名以.BAK结尾的文件。一旦被找到,则直接删除。注意: 毫无疑问,在使用-delete操作时你一定要格外小心。最好先用-print操作确认搜索结果后再执行-delete删除命令。 在我们继续讲下一个知识点前,先来补充介绍一下逻辑运算是如何影响find的action操作的。仔细揣摩下面的命令。 find ~ -type f -name '*.BAK' -print 正如我们所知道的,该命令行用来查找所有文件名以.BAK结尾的普通文件(-type f)并且以标准形式(-print)输出 每个匹配文件的相关路径名。然而,该命令行之所以照这样的方式执行是由每个test选项和action选项之间的逻辑关系决定的。记住,每个test选项和action选项之间默认的逻辑关系是与(and)逻辑。下面的命令行逻辑关系能看得更清楚些。 find ~ -type f -and -name '*.BAK' -and –print 如上便是完整的表达式,而表17-7便列出了逻辑运算符是如何影响action操作的。 表17-7便列出了逻辑运算符 test选项与action选项之间的逻辑关系决定了它们的执行情况,所以test选项和action选项的顺序很重要。例如,如果重新排列这些test选项和action选项,并将-print操作作为逻辑运算的第一个操作数,那么命令行的运行结果将会有很大的不同。 find ~ -print -and -type f -and -name '*.BAK' 此命令行会把每个文件显示出来(因为-print操作运算值总是为真),然后再对文件类型以及特定的文件扩展名进行匹配检查。 现在可以实际应用find命令了。首先让我们创建一个包含很多子目录及文件的playground文件夹平台。 [me@linuxbox ~]$mkdir -p playground/dir-{00{1..9},0{10..99},100} [me@linuxbox ~]$touch playground/dir-{00{1..9},0{10..99},100}/file-{A..Z} 不得不惊叹于Linux命令行的威力!简单的两行命令,就创建了一个包含100个子目录的playground文件夹,并且每个子目录中又包含26个空文件。你可以试试用图形用户界面GUI能否这么快得达到效果! 我们用来创造这个奇迹的方法包含一个熟悉的命令mkdir、一个奇异的shell花括号扩展以及一个新命令touch。mkdir命令结合-p选项(-p选项使mkdir命令按指定的路径创建父目录)的同时用花括号扩展,便完成了100个目录的创建。 touch命令一般用于设定或是更新文件的修改时间。然而,当文件名参数是一个不存在的文件时,那么该命令就会创建一个空文件。 playground文件夹里,总共创建了100个叫做file-A的文件。现在,我们可以查找它们。 me@linuxbox ~]$find playground -type f -name 'file-A' 请注意,与ls命令不同,find命令不会产生有排列顺序的结果,其输出顺序是由在存储设备中的布局决定的。下面的命令行验证了该文件夹确实有100个file-A文件。 下面来看一个根据文件的修改时间查找文件的例子,这在创建备份文件以及按时间顺序排列文件时非常有用。首先需要创建一个用作比较修改时间的参照文件。 [me@linuxbox ~]$touch playground/timestamp 该命令行创建了一个名为timestamp的空文件,并将当前时刻设为该文件的修改时间。我们可以使用另外一个便捷的命令stat来检验执行效果,stat命令可以说是ls的增强版,该命令会将系统所掌握文件的所有信息及属性全部显示出来。 [me@linuxbox ~]$stat playground/timestamp File:`playground/timestamp' 当我们再一次对此文件执行touch命令并用stat命令检验时,会发现文件的时间得到了更新。 接下来,我们便可以用find命令更新playground文件夹里的一些文件。 [me@linuxbox ~]$find playground -type f -name 'file-B' -exec touch '{}' ';' 该命令行更新了playground文件夹里面叫做file-B的所有文件。下面我们通过比较参照文件timestamp与其他文件的修改时间,使用find命令查找刚刚被更新的文件。 命令行的运行结果包含100个文件名为file-B的文件。由于我们是在对timestamp文件执行了touch命令之后,才对playground文件夹中对名为file-B的所有文件执行了touch操作,所以它们现在要比timestamp文件新,从而我们可选用-newer test选项来查找。 (编辑:成都站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |